home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / perl / 5.10.0 / Math / BigInt / Calc.pm next >
Encoding:
Perl POD Document  |  2009-06-26  |  71.3 KB  |  2,613 lines

  1. package Math::BigInt::Calc;
  2.  
  3. use 5.006;
  4. use strict;
  5. # use warnings;    # dont use warnings for older Perls
  6.  
  7. our $VERSION = '0.52';
  8.  
  9. # Package to store unsigned big integers in decimal and do math with them
  10.  
  11. # Internally the numbers are stored in an array with at least 1 element, no
  12. # leading zero parts (except the first) and in base 1eX where X is determined
  13. # automatically at loading time to be the maximum possible value
  14.  
  15. # todo:
  16. # - fully remove funky $# stuff in div() (maybe - that code scares me...)
  17.  
  18. # USE_MUL: due to problems on certain os (os390, posix-bc) "* 1e-5" is used
  19. # instead of "/ 1e5" at some places, (marked with USE_MUL). Other platforms
  20. # BS2000, some Crays need USE_DIV instead.
  21. # The BEGIN block is used to determine which of the two variants gives the
  22. # correct result.
  23.  
  24. # Beware of things like:
  25. # $i = $i * $y + $car; $car = int($i / $BASE); $i = $i % $BASE;
  26. # This works on x86, but fails on ARM (SA1100, iPAQ) due to whoknows what
  27. # reasons. So, use this instead (slower, but correct):
  28. # $i = $i * $y + $car; $car = int($i / $BASE); $i -= $BASE * $car;
  29.  
  30. ##############################################################################
  31. # global constants, flags and accessory
  32.  
  33. # announce that we are compatible with MBI v1.83 and up
  34. sub api_version () { 2; }
  35.  
  36. # constants for easier life
  37. my ($BASE,$BASE_LEN,$RBASE,$MAX_VAL);
  38. my ($AND_BITS,$XOR_BITS,$OR_BITS);
  39. my ($AND_MASK,$XOR_MASK,$OR_MASK);
  40.  
  41. sub _base_len 
  42.   {
  43.   # Set/get the BASE_LEN and assorted other, connected values.
  44.   # Used only by the testsuite, the set variant is used only by the BEGIN
  45.   # block below:
  46.   shift;
  47.  
  48.   my ($b, $int) = @_;
  49.   if (defined $b)
  50.     {
  51.     # avoid redefinitions
  52.     undef &_mul;
  53.     undef &_div;
  54.  
  55.     if ($] >= 5.008 && $int && $b > 7)
  56.       {
  57.       $BASE_LEN = $b;
  58.       *_mul = \&_mul_use_div_64;
  59.       *_div = \&_div_use_div_64;
  60.       $BASE = int("1e".$BASE_LEN);
  61.       $MAX_VAL = $BASE-1;
  62.       return $BASE_LEN unless wantarray;
  63.       return ($BASE_LEN, $AND_BITS, $XOR_BITS, $OR_BITS, $BASE_LEN, $MAX_VAL, $BASE);
  64.       }
  65.  
  66.     # find whether we can use mul or div in mul()/div()
  67.     $BASE_LEN = $b+1;
  68.     my $caught = 0;
  69.     while (--$BASE_LEN > 5)
  70.       {
  71.       $BASE = int("1e".$BASE_LEN);
  72.       $RBASE = abs('1e-'.$BASE_LEN);            # see USE_MUL
  73.       $caught = 0;
  74.       $caught += 1 if (int($BASE * $RBASE) != 1);    # should be 1
  75.       $caught += 2 if (int($BASE / $BASE) != 1);    # should be 1
  76.       last if $caught != 3;
  77.       }
  78.     $BASE = int("1e".$BASE_LEN);
  79.     $RBASE = abs('1e-'.$BASE_LEN);            # see USE_MUL
  80.     $MAX_VAL = $BASE-1;
  81.    
  82.     # ($caught & 1) != 0 => cannot use MUL
  83.     # ($caught & 2) != 0 => cannot use DIV
  84.     if ($caught == 2)                # 2
  85.       {
  86.       # must USE_MUL since we cannot use DIV
  87.       *_mul = \&_mul_use_mul;
  88.       *_div = \&_div_use_mul;
  89.       }
  90.     else                    # 0 or 1
  91.       {
  92.       # can USE_DIV instead
  93.       *_mul = \&_mul_use_div;
  94.       *_div = \&_div_use_div;
  95.       }
  96.     }
  97.   return $BASE_LEN unless wantarray;
  98.   return ($BASE_LEN, $AND_BITS, $XOR_BITS, $OR_BITS, $BASE_LEN, $MAX_VAL, $BASE);
  99.   }
  100.  
  101. sub _new
  102.   {
  103.   # (ref to string) return ref to num_array
  104.   # Convert a number from string format (without sign) to internal base
  105.   # 1ex format. Assumes normalized value as input.
  106.   my $il = length($_[1])-1;
  107.  
  108.   # < BASE_LEN due len-1 above
  109.   return [ int($_[1]) ] if $il < $BASE_LEN;    # shortcut for short numbers
  110.  
  111.   # this leaves '00000' instead of int 0 and will be corrected after any op
  112.   [ reverse(unpack("a" . ($il % $BASE_LEN+1) 
  113.     . ("a$BASE_LEN" x ($il / $BASE_LEN)), $_[1])) ];
  114.   }                                                                             
  115.  
  116. BEGIN
  117.   {
  118.   # from Daniel Pfeiffer: determine largest group of digits that is precisely
  119.   # multipliable with itself plus carry
  120.   # Test now changed to expect the proper pattern, not a result off by 1 or 2
  121.   my ($e, $num) = 3;    # lowest value we will use is 3+1-1 = 3
  122.   do 
  123.     {
  124.     $num = ('9' x ++$e) + 0;
  125.     $num *= $num + 1.0;
  126.     } while ("$num" =~ /9{$e}0{$e}/);    # must be a certain pattern
  127.   $e--;                 # last test failed, so retract one step
  128.   # the limits below brush the problems with the test above under the rug:
  129.   # the test should be able to find the proper $e automatically
  130.   $e = 5 if $^O =~ /^uts/;    # UTS get's some special treatment
  131.   $e = 5 if $^O =~ /^unicos/;    # unicos is also problematic (6 seems to work
  132.                 # there, but we play safe)
  133.  
  134.   my $int = 0;
  135.   if ($e > 7)
  136.     {
  137.     use integer;
  138.     my $e1 = 7;
  139.     $num = 7;
  140.     do 
  141.       {
  142.       $num = ('9' x ++$e1) + 0;
  143.       $num *= $num + 1;
  144.       } while ("$num" =~ /9{$e1}0{$e1}/);    # must be a certain pattern
  145.     $e1--;                     # last test failed, so retract one step
  146.     if ($e1 > 7)
  147.       { 
  148.       $int = 1; $e = $e1; 
  149.       }
  150.     }
  151.  
  152.   __PACKAGE__->_base_len($e,$int);    # set and store
  153.  
  154.   use integer;
  155.   # find out how many bits _and, _or and _xor can take (old default = 16)
  156.   # I don't think anybody has yet 128 bit scalars, so let's play safe.
  157.   local $^W = 0;    # don't warn about 'nonportable number'
  158.   $AND_BITS = 15; $XOR_BITS = 15; $OR_BITS = 15;
  159.  
  160.   # find max bits, we will not go higher than numberofbits that fit into $BASE
  161.   # to make _and etc simpler (and faster for smaller, slower for large numbers)
  162.   my $max = 16;
  163.   while (2 ** $max < $BASE) { $max++; }
  164.   {
  165.     no integer;
  166.     $max = 16 if $] < 5.006;    # older Perls might not take >16 too well
  167.   }
  168.   my ($x,$y,$z);
  169.   do {
  170.     $AND_BITS++;
  171.     $x = CORE::oct('0b' . '1' x $AND_BITS); $y = $x & $x;
  172.     $z = (2 ** $AND_BITS) - 1;
  173.     } while ($AND_BITS < $max && $x == $z && $y == $x);
  174.   $AND_BITS --;                        # retreat one step
  175.   do {
  176.     $XOR_BITS++;
  177.     $x = CORE::oct('0b' . '1' x $XOR_BITS); $y = $x ^ 0;
  178.     $z = (2 ** $XOR_BITS) - 1;
  179.     } while ($XOR_BITS < $max && $x == $z && $y == $x);
  180.   $XOR_BITS --;                        # retreat one step
  181.   do {
  182.     $OR_BITS++;
  183.     $x = CORE::oct('0b' . '1' x $OR_BITS); $y = $x | $x;
  184.     $z = (2 ** $OR_BITS) - 1;
  185.     } while ($OR_BITS < $max && $x == $z && $y == $x);
  186.   $OR_BITS --;                        # retreat one step
  187.   
  188.   $AND_MASK = __PACKAGE__->_new( ( 2 ** $AND_BITS ));
  189.   $XOR_MASK = __PACKAGE__->_new( ( 2 ** $XOR_BITS ));
  190.   $OR_MASK = __PACKAGE__->_new( ( 2 ** $OR_BITS ));
  191.  
  192.   # We can compute the approximate lenght no faster than the real length:
  193.   *_alen = \&_len;
  194.   }
  195.  
  196. ###############################################################################
  197.  
  198. sub _zero
  199.   {
  200.   # create a zero
  201.   [ 0 ];
  202.   }
  203.  
  204. sub _one
  205.   {
  206.   # create a one
  207.   [ 1 ];
  208.   }
  209.  
  210. sub _two
  211.   {
  212.   # create a two (used internally for shifting)
  213.   [ 2 ];
  214.   }
  215.  
  216. sub _ten
  217.   {
  218.   # create a 10 (used internally for shifting)
  219.   [ 10 ];
  220.   }
  221.  
  222. sub _1ex
  223.   {
  224.   # create a 1Ex
  225.   my $rem = $_[1] % $BASE_LEN;        # remainder
  226.   my $parts = $_[1] / $BASE_LEN;    # parts
  227.  
  228.   # 000000, 000000, 100 
  229.   [ (0) x $parts, '1' . ('0' x $rem) ];
  230.   }
  231.  
  232. sub _copy
  233.   {
  234.   # make a true copy
  235.   [ @{$_[1]} ];
  236.   }
  237.  
  238. # catch and throw away
  239. sub import { }
  240.  
  241. ##############################################################################
  242. # convert back to string and number
  243.  
  244. sub _str
  245.   {
  246.   # (ref to BINT) return num_str
  247.   # Convert number from internal base 100000 format to string format.
  248.   # internal format is always normalized (no leading zeros, "-0" => "+0")
  249.   my $ar = $_[1];
  250.  
  251.   my $l = scalar @$ar;                # number of parts
  252.   if ($l < 1)                    # should not happen
  253.     {
  254.     require Carp;
  255.     Carp::croak("$_[1] has no elements");
  256.     }
  257.  
  258.   my $ret = "";
  259.   # handle first one different to strip leading zeros from it (there are no
  260.   # leading zero parts in internal representation)
  261.   $l --; $ret .= int($ar->[$l]); $l--;
  262.   # Interestingly, the pre-padd method uses more time
  263.   # the old grep variant takes longer (14 vs. 10 sec)
  264.   my $z = '0' x ($BASE_LEN-1);                            
  265.   while ($l >= 0)
  266.     {
  267.     $ret .= substr($z.$ar->[$l],-$BASE_LEN); # fastest way I could think of
  268.     $l--;
  269.     }
  270.   $ret;
  271.   }                                                                             
  272.  
  273. sub _num
  274.   {
  275.   # Make a number (scalar int/float) from a BigInt object 
  276.   my $x = $_[1];
  277.  
  278.   return 0+$x->[0] if scalar @$x == 1;  # below $BASE
  279.   my $fac = 1;
  280.   my $num = 0;
  281.   foreach (@$x)
  282.     {
  283.     $num += $fac*$_; $fac *= $BASE;
  284.     }
  285.   $num; 
  286.   }
  287.  
  288. ##############################################################################
  289. # actual math code
  290.  
  291. sub _add
  292.   {
  293.   # (ref to int_num_array, ref to int_num_array)
  294.   # routine to add two base 1eX numbers
  295.   # stolen from Knuth Vol 2 Algorithm A pg 231
  296.   # there are separate routines to add and sub as per Knuth pg 233
  297.   # This routine clobbers up array x, but not y.
  298.  
  299.   my ($c,$x,$y) = @_;
  300.  
  301.   return $x if (@$y == 1) && $y->[0] == 0;        # $x + 0 => $x
  302.   if ((@$x == 1) && $x->[0] == 0)            # 0 + $y => $y->copy
  303.     {
  304.     # twice as slow as $x = [ @$y ], but nec. to retain $x as ref :(
  305.     @$x = @$y; return $x;        
  306.     }
  307.  
  308.   # for each in Y, add Y to X and carry. If after that, something is left in
  309.   # X, foreach in X add carry to X and then return X, carry
  310.   # Trades one "$j++" for having to shift arrays
  311.   my $i; my $car = 0; my $j = 0;
  312.   for $i (@$y)
  313.     {
  314.     $x->[$j] -= $BASE if $car = (($x->[$j] += $i + $car) >= $BASE) ? 1 : 0;
  315.     $j++;
  316.     }
  317.   while ($car != 0)
  318.     {
  319.     $x->[$j] -= $BASE if $car = (($x->[$j] += $car) >= $BASE) ? 1 : 0; $j++;
  320.     }
  321.   $x;
  322.   }                                                                             
  323.  
  324. sub _inc
  325.   {
  326.   # (ref to int_num_array, ref to int_num_array)
  327.   # Add 1 to $x, modify $x in place
  328.   my ($c,$x) = @_;
  329.  
  330.   for my $i (@$x)
  331.     {
  332.     return $x if (($i += 1) < $BASE);        # early out
  333.     $i = 0;                    # overflow, next
  334.     }
  335.   push @$x,1 if (($x->[-1] || 0) == 0);        # last overflowed, so extend
  336.   $x;
  337.   }                                                                             
  338.  
  339. sub _dec
  340.   {
  341.   # (ref to int_num_array, ref to int_num_array)
  342.   # Sub 1 from $x, modify $x in place
  343.   my ($c,$x) = @_;
  344.  
  345.   my $MAX = $BASE-1;                # since MAX_VAL based on BASE
  346.   for my $i (@$x)
  347.     {
  348.     last if (($i -= 1) >= 0);            # early out
  349.     $i = $MAX;                    # underflow, next
  350.     }
  351.   pop @$x if $x->[-1] == 0 && @$x > 1;        # last underflowed (but leave 0)
  352.   $x;
  353.   }                                                                             
  354.  
  355. sub _sub
  356.   {
  357.   # (ref to int_num_array, ref to int_num_array, swap)
  358.   # subtract base 1eX numbers -- stolen from Knuth Vol 2 pg 232, $x > $y
  359.   # subtract Y from X by modifying x in place
  360.   my ($c,$sx,$sy,$s) = @_;
  361.  
  362.   my $car = 0; my $i; my $j = 0;
  363.   if (!$s)
  364.     {
  365.     for $i (@$sx)
  366.       {
  367.       last unless defined $sy->[$j] || $car;
  368.       $i += $BASE if $car = (($i -= ($sy->[$j] || 0) + $car) < 0); $j++;
  369.       }
  370.     # might leave leading zeros, so fix that
  371.     return __strip_zeros($sx);
  372.     }
  373.   for $i (@$sx)
  374.     {
  375.     # we can't do an early out if $x is < than $y, since we
  376.     # need to copy the high chunks from $y. Found by Bob Mathews.
  377.     #last unless defined $sy->[$j] || $car;
  378.     $sy->[$j] += $BASE
  379.      if $car = (($sy->[$j] = $i-($sy->[$j]||0) - $car) < 0);
  380.     $j++;
  381.     }
  382.   # might leave leading zeros, so fix that
  383.   __strip_zeros($sy);
  384.   }                                                                             
  385.  
  386. sub _mul_use_mul
  387.   {
  388.   # (ref to int_num_array, ref to int_num_array)
  389.   # multiply two numbers in internal representation
  390.   # modifies first arg, second need not be different from first
  391.   my ($c,$xv,$yv) = @_;
  392.  
  393.   if (@$yv == 1)
  394.     {
  395.     # shortcut for two very short numbers (improved by Nathan Zook)
  396.     # works also if xv and yv are the same reference, and handles also $x == 0
  397.     if (@$xv == 1)
  398.       {
  399.       if (($xv->[0] *= $yv->[0]) >= $BASE)
  400.          {
  401.          $xv->[0] = $xv->[0] - ($xv->[1] = int($xv->[0] * $RBASE)) * $BASE;
  402.          };
  403.       return $xv;
  404.       }
  405.     # $x * 0 => 0
  406.     if ($yv->[0] == 0)
  407.       {
  408.       @$xv = (0);
  409.       return $xv;
  410.       }
  411.     # multiply a large number a by a single element one, so speed up
  412.     my $y = $yv->[0]; my $car = 0;
  413.     foreach my $i (@$xv)
  414.       {
  415.       $i = $i * $y + $car; $car = int($i * $RBASE); $i -= $car * $BASE;
  416.       }
  417.     push @$xv, $car if $car != 0;
  418.     return $xv;
  419.     }
  420.   # shortcut for result $x == 0 => result = 0
  421.   return $xv if ( ((@$xv == 1) && ($xv->[0] == 0)) ); 
  422.  
  423.   # since multiplying $x with $x fails, make copy in this case
  424.   $yv = [@$xv] if $xv == $yv;    # same references?
  425.  
  426.   my @prod = (); my ($prod,$car,$cty,$xi,$yi);
  427.  
  428.   for $xi (@$xv)
  429.     {
  430.     $car = 0; $cty = 0;
  431.  
  432.     # slow variant
  433. #    for $yi (@$yv)
  434. #      {
  435. #      $prod = $xi * $yi + ($prod[$cty] || 0) + $car;
  436. #      $prod[$cty++] =
  437. #       $prod - ($car = int($prod * RBASE)) * $BASE;  # see USE_MUL
  438. #      }
  439. #    $prod[$cty] += $car if $car; # need really to check for 0?
  440. #    $xi = shift @prod;
  441.  
  442.     # faster variant
  443.     # looping through this if $xi == 0 is silly - so optimize it away!
  444.     $xi = (shift @prod || 0), next if $xi == 0;
  445.     for $yi (@$yv)
  446.       {
  447.       $prod = $xi * $yi + ($prod[$cty] || 0) + $car;
  448. ##     this is actually a tad slower
  449. ##        $prod = $prod[$cty]; $prod += ($car + $xi * $yi);    # no ||0 here
  450.       $prod[$cty++] =
  451.        $prod - ($car = int($prod * $RBASE)) * $BASE;  # see USE_MUL
  452.       }
  453.     $prod[$cty] += $car if $car; # need really to check for 0?
  454.     $xi = shift @prod || 0;    # || 0 makes v5.005_3 happy
  455.     }
  456.   push @$xv, @prod;
  457.   # can't have leading zeros
  458. #  __strip_zeros($xv);
  459.   $xv;
  460.   }                                                                             
  461.  
  462. sub _mul_use_div_64
  463.   {
  464.   # (ref to int_num_array, ref to int_num_array)
  465.   # multiply two numbers in internal representation
  466.   # modifies first arg, second need not be different from first
  467.   # works for 64 bit integer with "use integer"
  468.   my ($c,$xv,$yv) = @_;
  469.  
  470.   use integer;
  471.   if (@$yv == 1)
  472.     {
  473.     # shortcut for two small numbers, also handles $x == 0
  474.     if (@$xv == 1)
  475.       {
  476.       # shortcut for two very short numbers (improved by Nathan Zook)
  477.       # works also if xv and yv are the same reference, and handles also $x == 0
  478.       if (($xv->[0] *= $yv->[0]) >= $BASE)
  479.           {
  480.           $xv->[0] =
  481.               $xv->[0] - ($xv->[1] = $xv->[0] / $BASE) * $BASE;
  482.           };
  483.       return $xv;
  484.       }
  485.     # $x * 0 => 0
  486.     if ($yv->[0] == 0)
  487.       {
  488.       @$xv = (0);
  489.       return $xv;
  490.       }
  491.     # multiply a large number a by a single element one, so speed up
  492.     my $y = $yv->[0]; my $car = 0;
  493.     foreach my $i (@$xv)
  494.       {
  495.       #$i = $i * $y + $car; $car = $i / $BASE; $i -= $car * $BASE;
  496.       $i = $i * $y + $car; $i -= ($car = $i / $BASE) * $BASE;
  497.       }
  498.     push @$xv, $car if $car != 0;
  499.     return $xv;
  500.     }
  501.   # shortcut for result $x == 0 => result = 0
  502.   return $xv if ( ((@$xv == 1) && ($xv->[0] == 0)) ); 
  503.  
  504.   # since multiplying $x with $x fails, make copy in this case
  505.   $yv = [@$xv] if $xv == $yv;    # same references?
  506.  
  507.   my @prod = (); my ($prod,$car,$cty,$xi,$yi);
  508.   for $xi (@$xv)
  509.     {
  510.     $car = 0; $cty = 0;
  511.     # looping through this if $xi == 0 is silly - so optimize it away!
  512.     $xi = (shift @prod || 0), next if $xi == 0;
  513.     for $yi (@$yv)
  514.       {
  515.       $prod = $xi * $yi + ($prod[$cty] || 0) + $car;
  516.       $prod[$cty++] = $prod - ($car = $prod / $BASE) * $BASE;
  517.       }
  518.     $prod[$cty] += $car if $car; # need really to check for 0?
  519.     $xi = shift @prod || 0;    # || 0 makes v5.005_3 happy
  520.     }
  521.   push @$xv, @prod;
  522.   $xv;
  523.   }                                                                             
  524.  
  525. sub _mul_use_div
  526.   {
  527.   # (ref to int_num_array, ref to int_num_array)
  528.   # multiply two numbers in internal representation
  529.   # modifies first arg, second need not be different from first
  530.   my ($c,$xv,$yv) = @_;
  531.  
  532.   if (@$yv == 1)
  533.     {
  534.     # shortcut for two small numbers, also handles $x == 0
  535.     if (@$xv == 1)
  536.       {
  537.       # shortcut for two very short numbers (improved by Nathan Zook)
  538.       # works also if xv and yv are the same reference, and handles also $x == 0
  539.       if (($xv->[0] *= $yv->[0]) >= $BASE)
  540.           {
  541.           $xv->[0] =
  542.               $xv->[0] - ($xv->[1] = int($xv->[0] / $BASE)) * $BASE;
  543.           };
  544.       return $xv;
  545.       }
  546.     # $x * 0 => 0
  547.     if ($yv->[0] == 0)
  548.       {
  549.       @$xv = (0);
  550.       return $xv;
  551.       }
  552.     # multiply a large number a by a single element one, so speed up
  553.     my $y = $yv->[0]; my $car = 0;
  554.     foreach my $i (@$xv)
  555.       {
  556.       $i = $i * $y + $car; $car = int($i / $BASE); $i -= $car * $BASE;
  557.       # This (together with use integer;) does not work on 32-bit Perls
  558.       #$i = $i * $y + $car; $i -= ($car = $i / $BASE) * $BASE;
  559.       }
  560.     push @$xv, $car if $car != 0;
  561.     return $xv;
  562.     }
  563.   # shortcut for result $x == 0 => result = 0
  564.   return $xv if ( ((@$xv == 1) && ($xv->[0] == 0)) ); 
  565.  
  566.   # since multiplying $x with $x fails, make copy in this case
  567.   $yv = [@$xv] if $xv == $yv;    # same references?
  568.  
  569.   my @prod = (); my ($prod,$car,$cty,$xi,$yi);
  570.   for $xi (@$xv)
  571.     {
  572.     $car = 0; $cty = 0;
  573.     # looping through this if $xi == 0 is silly - so optimize it away!
  574.     $xi = (shift @prod || 0), next if $xi == 0;
  575.     for $yi (@$yv)
  576.       {
  577.       $prod = $xi * $yi + ($prod[$cty] || 0) + $car;
  578.       $prod[$cty++] = $prod - ($car = int($prod / $BASE)) * $BASE;
  579.       }
  580.     $prod[$cty] += $car if $car; # need really to check for 0?
  581.     $xi = shift @prod || 0;    # || 0 makes v5.005_3 happy
  582.     }
  583.   push @$xv, @prod;
  584.   # can't have leading zeros
  585. #  __strip_zeros($xv);
  586.   $xv;
  587.   }                                                                             
  588.  
  589. sub _div_use_mul
  590.   {
  591.   # ref to array, ref to array, modify first array and return remainder if 
  592.   # in list context
  593.  
  594.   # see comments in _div_use_div() for more explanations
  595.  
  596.   my ($c,$x,$yorg) = @_;
  597.   
  598.   # the general div algorithmn here is about O(N*N) and thus quite slow, so
  599.   # we first check for some special cases and use shortcuts to handle them.
  600.  
  601.   # This works, because we store the numbers in a chunked format where each
  602.   # element contains 5..7 digits (depending on system).
  603.  
  604.   # if both numbers have only one element:
  605.   if (@$x == 1 && @$yorg == 1)
  606.     {
  607.     # shortcut, $yorg and $x are two small numbers
  608.     if (wantarray)
  609.       {
  610.       my $r = [ $x->[0] % $yorg->[0] ];
  611.       $x->[0] = int($x->[0] / $yorg->[0]);
  612.       return ($x,$r); 
  613.       }
  614.     else
  615.       {
  616.       $x->[0] = int($x->[0] / $yorg->[0]);
  617.       return $x; 
  618.       }
  619.     }
  620.  
  621.   # if x has more than one, but y has only one element:
  622.   if (@$yorg == 1)
  623.     {
  624.     my $rem;
  625.     $rem = _mod($c,[ @$x ],$yorg) if wantarray;
  626.  
  627.     # shortcut, $y is < $BASE
  628.     my $j = scalar @$x; my $r = 0; 
  629.     my $y = $yorg->[0]; my $b;
  630.     while ($j-- > 0)
  631.       {
  632.       $b = $r * $BASE + $x->[$j];
  633.       $x->[$j] = int($b/$y);
  634.       $r = $b % $y;
  635.       }
  636.     pop @$x if @$x > 1 && $x->[-1] == 0;    # splice up a leading zero 
  637.     return ($x,$rem) if wantarray;
  638.     return $x;
  639.     }
  640.  
  641.   # now x and y have more than one element
  642.  
  643.   # check whether y has more elements than x, if yet, the result will be 0
  644.   if (@$yorg > @$x)
  645.     {
  646.     my $rem;
  647.     $rem = [@$x] if wantarray;                  # make copy
  648.     splice (@$x,1);                             # keep ref to original array
  649.     $x->[0] = 0;                                # set to 0
  650.     return ($x,$rem) if wantarray;              # including remainder?
  651.     return $x;                    # only x, which is [0] now
  652.     }
  653.   # check whether the numbers have the same number of elements, in that case
  654.   # the result will fit into one element and can be computed efficiently
  655.   if (@$yorg == @$x)
  656.     {
  657.     my $rem;
  658.     # if $yorg has more digits than $x (it's leading element is longer than
  659.     # the one from $x), the result will also be 0:
  660.     if (length(int($yorg->[-1])) > length(int($x->[-1])))
  661.       {
  662.       $rem = [@$x] if wantarray;        # make copy
  663.       splice (@$x,1);                # keep ref to org array
  664.       $x->[0] = 0;                # set to 0
  665.       return ($x,$rem) if wantarray;        # including remainder?
  666.       return $x;
  667.       }
  668.     # now calculate $x / $yorg
  669.     if (length(int($yorg->[-1])) == length(int($x->[-1])))
  670.       {
  671.       # same length, so make full compare
  672.  
  673.       my $a = 0; my $j = scalar @$x - 1;
  674.       # manual way (abort if unequal, good for early ne)
  675.       while ($j >= 0)
  676.         {
  677.         last if ($a = $x->[$j] - $yorg->[$j]); $j--;
  678.         }
  679.       # $a contains the result of the compare between X and Y
  680.       # a < 0: x < y, a == 0: x == y, a > 0: x > y
  681.       if ($a <= 0)
  682.         {
  683.         $rem = [ 0 ];                   # a = 0 => x == y => rem 0
  684.         $rem = [@$x] if $a != 0;        # a < 0 => x < y => rem = x
  685.         splice(@$x,1);                  # keep single element
  686.         $x->[0] = 0;                    # if $a < 0
  687.         $x->[0] = 1 if $a == 0;         # $x == $y
  688.         return ($x,$rem) if wantarray;
  689.         return $x;
  690.         }
  691.       # $x >= $y, so proceed normally
  692.       }
  693.     }
  694.  
  695.   # all other cases:
  696.  
  697.   my $y = [ @$yorg ];                # always make copy to preserve
  698.  
  699.   my ($car,$bar,$prd,$dd,$xi,$yi,@q,$v2,$v1,@d,$tmp,$q,$u2,$u1,$u0);
  700.  
  701.   $car = $bar = $prd = 0;
  702.   if (($dd = int($BASE/($y->[-1]+1))) != 1) 
  703.     {
  704.     for $xi (@$x) 
  705.       {
  706.       $xi = $xi * $dd + $car;
  707.       $xi -= ($car = int($xi * $RBASE)) * $BASE;    # see USE_MUL
  708.       }
  709.     push(@$x, $car); $car = 0;
  710.     for $yi (@$y) 
  711.       {
  712.       $yi = $yi * $dd + $car;
  713.       $yi -= ($car = int($yi * $RBASE)) * $BASE;    # see USE_MUL
  714.       }
  715.     }
  716.   else 
  717.     {
  718.     push(@$x, 0);
  719.     }
  720.   @q = (); ($v2,$v1) = @$y[-2,-1];
  721.   $v2 = 0 unless $v2;
  722.   while ($#$x > $#$y) 
  723.     {
  724.     ($u2,$u1,$u0) = @$x[-3..-1];
  725.     $u2 = 0 unless $u2;
  726.     #warn "oups v1 is 0, u0: $u0 $y->[-2] $y->[-1] l ",scalar @$y,"\n"
  727.     # if $v1 == 0;
  728.     $q = (($u0 == $v1) ? $MAX_VAL : int(($u0*$BASE+$u1)/$v1));
  729.     --$q while ($v2*$q > ($u0*$BASE+$u1-$q*$v1)*$BASE+$u2);
  730.     if ($q)
  731.       {
  732.       ($car, $bar) = (0,0);
  733.       for ($yi = 0, $xi = $#$x-$#$y-1; $yi <= $#$y; ++$yi,++$xi) 
  734.         {
  735.         $prd = $q * $y->[$yi] + $car;
  736.         $prd -= ($car = int($prd * $RBASE)) * $BASE;    # see USE_MUL
  737.     $x->[$xi] += $BASE if ($bar = (($x->[$xi] -= $prd + $bar) < 0));
  738.     }
  739.       if ($x->[-1] < $car + $bar) 
  740.         {
  741.         $car = 0; --$q;
  742.     for ($yi = 0, $xi = $#$x-$#$y-1; $yi <= $#$y; ++$yi,++$xi) 
  743.           {
  744.       $x->[$xi] -= $BASE
  745.        if ($car = (($x->[$xi] += $y->[$yi] + $car) >= $BASE));
  746.       }
  747.     }   
  748.       }
  749.     pop(@$x);
  750.     unshift(@q, $q);
  751.     }
  752.   if (wantarray) 
  753.     {
  754.     @d = ();
  755.     if ($dd != 1)  
  756.       {
  757.       $car = 0; 
  758.       for $xi (reverse @$x) 
  759.         {
  760.         $prd = $car * $BASE + $xi;
  761.         $car = $prd - ($tmp = int($prd / $dd)) * $dd; # see USE_MUL
  762.         unshift(@d, $tmp);
  763.         }
  764.       }
  765.     else 
  766.       {
  767.       @d = @$x;
  768.       }
  769.     @$x = @q;
  770.     my $d = \@d; 
  771.     __strip_zeros($x);
  772.     __strip_zeros($d);
  773.     return ($x,$d);
  774.     }
  775.   @$x = @q;
  776.   __strip_zeros($x);
  777.   $x;
  778.   }
  779.  
  780. sub _div_use_div_64
  781.   {
  782.   # ref to array, ref to array, modify first array and return remainder if 
  783.   # in list context
  784.   # This version works on 64 bit integers
  785.   my ($c,$x,$yorg) = @_;
  786.  
  787.   use integer;
  788.   # the general div algorithmn here is about O(N*N) and thus quite slow, so
  789.   # we first check for some special cases and use shortcuts to handle them.
  790.  
  791.   # This works, because we store the numbers in a chunked format where each
  792.   # element contains 5..7 digits (depending on system).
  793.  
  794.   # if both numbers have only one element:
  795.   if (@$x == 1 && @$yorg == 1)
  796.     {
  797.     # shortcut, $yorg and $x are two small numbers
  798.     if (wantarray)
  799.       {
  800.       my $r = [ $x->[0] % $yorg->[0] ];
  801.       $x->[0] = int($x->[0] / $yorg->[0]);
  802.       return ($x,$r); 
  803.       }
  804.     else
  805.       {
  806.       $x->[0] = int($x->[0] / $yorg->[0]);
  807.       return $x; 
  808.       }
  809.     }
  810.   # if x has more than one, but y has only one element:
  811.   if (@$yorg == 1)
  812.     {
  813.     my $rem;
  814.     $rem = _mod($c,[ @$x ],$yorg) if wantarray;
  815.  
  816.     # shortcut, $y is < $BASE
  817.     my $j = scalar @$x; my $r = 0; 
  818.     my $y = $yorg->[0]; my $b;
  819.     while ($j-- > 0)
  820.       {
  821.       $b = $r * $BASE + $x->[$j];
  822.       $x->[$j] = int($b/$y);
  823.       $r = $b % $y;
  824.       }
  825.     pop @$x if @$x > 1 && $x->[-1] == 0;    # splice up a leading zero 
  826.     return ($x,$rem) if wantarray;
  827.     return $x;
  828.     }
  829.   # now x and y have more than one element
  830.  
  831.   # check whether y has more elements than x, if yet, the result will be 0
  832.   if (@$yorg > @$x)
  833.     {
  834.     my $rem;
  835.     $rem = [@$x] if wantarray;            # make copy
  836.     splice (@$x,1);                # keep ref to original array
  837.     $x->[0] = 0;                # set to 0
  838.     return ($x,$rem) if wantarray;        # including remainder?
  839.     return $x;                    # only x, which is [0] now
  840.     }
  841.   # check whether the numbers have the same number of elements, in that case
  842.   # the result will fit into one element and can be computed efficiently
  843.   if (@$yorg == @$x)
  844.     {
  845.     my $rem;
  846.     # if $yorg has more digits than $x (it's leading element is longer than
  847.     # the one from $x), the result will also be 0:
  848.     if (length(int($yorg->[-1])) > length(int($x->[-1])))
  849.       {
  850.       $rem = [@$x] if wantarray;        # make copy
  851.       splice (@$x,1);                # keep ref to org array
  852.       $x->[0] = 0;                # set to 0
  853.       return ($x,$rem) if wantarray;        # including remainder?
  854.       return $x;
  855.       }
  856.     # now calculate $x / $yorg
  857.  
  858.     if (length(int($yorg->[-1])) == length(int($x->[-1])))
  859.       {
  860.       # same length, so make full compare
  861.  
  862.       my $a = 0; my $j = scalar @$x - 1;
  863.       # manual way (abort if unequal, good for early ne)
  864.       while ($j >= 0)
  865.         {
  866.         last if ($a = $x->[$j] - $yorg->[$j]); $j--;
  867.         }
  868.       # $a contains the result of the compare between X and Y
  869.       # a < 0: x < y, a == 0: x == y, a > 0: x > y
  870.       if ($a <= 0)
  871.         {
  872.         $rem = [ 0 ];            # a = 0 => x == y => rem 0
  873.         $rem = [@$x] if $a != 0;    # a < 0 => x < y => rem = x
  874.         splice(@$x,1);            # keep single element
  875.         $x->[0] = 0;            # if $a < 0
  876.         $x->[0] = 1 if $a == 0;     # $x == $y
  877.         return ($x,$rem) if wantarray;    # including remainder?
  878.         return $x;
  879.         }
  880.       # $x >= $y, so proceed normally
  881.  
  882.       }
  883.     }
  884.  
  885.   # all other cases:
  886.  
  887.   my $y = [ @$yorg ];                # always make copy to preserve
  888.  
  889.   my ($car,$bar,$prd,$dd,$xi,$yi,@q,$v2,$v1,@d,$tmp,$q,$u2,$u1,$u0);
  890.  
  891.   $car = $bar = $prd = 0;
  892.   if (($dd = int($BASE/($y->[-1]+1))) != 1) 
  893.     {
  894.     for $xi (@$x) 
  895.       {
  896.       $xi = $xi * $dd + $car;
  897.       $xi -= ($car = int($xi / $BASE)) * $BASE;
  898.       }
  899.     push(@$x, $car); $car = 0;
  900.     for $yi (@$y) 
  901.       {
  902.       $yi = $yi * $dd + $car;
  903.       $yi -= ($car = int($yi / $BASE)) * $BASE;
  904.       }
  905.     }
  906.   else 
  907.     {
  908.     push(@$x, 0);
  909.     }
  910.  
  911.   # @q will accumulate the final result, $q contains the current computed
  912.   # part of the final result
  913.  
  914.   @q = (); ($v2,$v1) = @$y[-2,-1];
  915.   $v2 = 0 unless $v2;
  916.   while ($#$x > $#$y) 
  917.     {
  918.     ($u2,$u1,$u0) = @$x[-3..-1];
  919.     $u2 = 0 unless $u2;
  920.     #warn "oups v1 is 0, u0: $u0 $y->[-2] $y->[-1] l ",scalar @$y,"\n"
  921.     # if $v1 == 0;
  922.     $q = (($u0 == $v1) ? $MAX_VAL : int(($u0*$BASE+$u1)/$v1));
  923.     --$q while ($v2*$q > ($u0*$BASE+$u1-$q*$v1)*$BASE+$u2);
  924.     if ($q)
  925.       {
  926.       ($car, $bar) = (0,0);
  927.       for ($yi = 0, $xi = $#$x-$#$y-1; $yi <= $#$y; ++$yi,++$xi) 
  928.         {
  929.         $prd = $q * $y->[$yi] + $car;
  930.         $prd -= ($car = int($prd / $BASE)) * $BASE;
  931.     $x->[$xi] += $BASE if ($bar = (($x->[$xi] -= $prd + $bar) < 0));
  932.     }
  933.       if ($x->[-1] < $car + $bar) 
  934.         {
  935.         $car = 0; --$q;
  936.     for ($yi = 0, $xi = $#$x-$#$y-1; $yi <= $#$y; ++$yi,++$xi) 
  937.           {
  938.       $x->[$xi] -= $BASE
  939.        if ($car = (($x->[$xi] += $y->[$yi] + $car) >= $BASE));
  940.       }
  941.     }   
  942.       }
  943.     pop(@$x); unshift(@q, $q);
  944.     }
  945.   if (wantarray) 
  946.     {
  947.     @d = ();
  948.     if ($dd != 1)  
  949.       {
  950.       $car = 0; 
  951.       for $xi (reverse @$x) 
  952.         {
  953.         $prd = $car * $BASE + $xi;
  954.         $car = $prd - ($tmp = int($prd / $dd)) * $dd;
  955.         unshift(@d, $tmp);
  956.         }
  957.       }
  958.     else 
  959.       {
  960.       @d = @$x;
  961.       }
  962.     @$x = @q;
  963.     my $d = \@d; 
  964.     __strip_zeros($x);
  965.     __strip_zeros($d);
  966.     return ($x,$d);
  967.     }
  968.   @$x = @q;
  969.   __strip_zeros($x);
  970.   $x;
  971.   }
  972.  
  973. sub _div_use_div
  974.   {
  975.   # ref to array, ref to array, modify first array and return remainder if 
  976.   # in list context
  977.   my ($c,$x,$yorg) = @_;
  978.  
  979.   # the general div algorithmn here is about O(N*N) and thus quite slow, so
  980.   # we first check for some special cases and use shortcuts to handle them.
  981.  
  982.   # This works, because we store the numbers in a chunked format where each
  983.   # element contains 5..7 digits (depending on system).
  984.  
  985.   # if both numbers have only one element:
  986.   if (@$x == 1 && @$yorg == 1)
  987.     {
  988.     # shortcut, $yorg and $x are two small numbers
  989.     if (wantarray)
  990.       {
  991.       my $r = [ $x->[0] % $yorg->[0] ];
  992.       $x->[0] = int($x->[0] / $yorg->[0]);
  993.       return ($x,$r); 
  994.       }
  995.     else
  996.       {
  997.       $x->[0] = int($x->[0] / $yorg->[0]);
  998.       return $x; 
  999.       }
  1000.     }
  1001.   # if x has more than one, but y has only one element:
  1002.   if (@$yorg == 1)
  1003.     {
  1004.     my $rem;
  1005.     $rem = _mod($c,[ @$x ],$yorg) if wantarray;
  1006.  
  1007.     # shortcut, $y is < $BASE
  1008.     my $j = scalar @$x; my $r = 0; 
  1009.     my $y = $yorg->[0]; my $b;
  1010.     while ($j-- > 0)
  1011.       {
  1012.       $b = $r * $BASE + $x->[$j];
  1013.       $x->[$j] = int($b/$y);
  1014.       $r = $b % $y;
  1015.       }
  1016.     pop @$x if @$x > 1 && $x->[-1] == 0;    # splice up a leading zero 
  1017.     return ($x,$rem) if wantarray;
  1018.     return $x;
  1019.     }
  1020.   # now x and y have more than one element
  1021.  
  1022.   # check whether y has more elements than x, if yet, the result will be 0
  1023.   if (@$yorg > @$x)
  1024.     {
  1025.     my $rem;
  1026.     $rem = [@$x] if wantarray;            # make copy
  1027.     splice (@$x,1);                # keep ref to original array
  1028.     $x->[0] = 0;                # set to 0
  1029.     return ($x,$rem) if wantarray;        # including remainder?
  1030.     return $x;                    # only x, which is [0] now
  1031.     }
  1032.   # check whether the numbers have the same number of elements, in that case
  1033.   # the result will fit into one element and can be computed efficiently
  1034.   if (@$yorg == @$x)
  1035.     {
  1036.     my $rem;
  1037.     # if $yorg has more digits than $x (it's leading element is longer than
  1038.     # the one from $x), the result will also be 0:
  1039.     if (length(int($yorg->[-1])) > length(int($x->[-1])))
  1040.       {
  1041.       $rem = [@$x] if wantarray;        # make copy
  1042.       splice (@$x,1);                # keep ref to org array
  1043.       $x->[0] = 0;                # set to 0
  1044.       return ($x,$rem) if wantarray;        # including remainder?
  1045.       return $x;
  1046.       }
  1047.     # now calculate $x / $yorg
  1048.  
  1049.     if (length(int($yorg->[-1])) == length(int($x->[-1])))
  1050.       {
  1051.       # same length, so make full compare
  1052.  
  1053.       my $a = 0; my $j = scalar @$x - 1;
  1054.       # manual way (abort if unequal, good for early ne)
  1055.       while ($j >= 0)
  1056.         {
  1057.         last if ($a = $x->[$j] - $yorg->[$j]); $j--;
  1058.         }
  1059.       # $a contains the result of the compare between X and Y
  1060.       # a < 0: x < y, a == 0: x == y, a > 0: x > y
  1061.       if ($a <= 0)
  1062.         {
  1063.         $rem = [ 0 ];            # a = 0 => x == y => rem 0
  1064.         $rem = [@$x] if $a != 0;    # a < 0 => x < y => rem = x
  1065.         splice(@$x,1);            # keep single element
  1066.         $x->[0] = 0;            # if $a < 0
  1067.         $x->[0] = 1 if $a == 0;     # $x == $y
  1068.         return ($x,$rem) if wantarray;    # including remainder?
  1069.         return $x;
  1070.         }
  1071.       # $x >= $y, so proceed normally
  1072.  
  1073.       }
  1074.     }
  1075.  
  1076.   # all other cases:
  1077.  
  1078.   my $y = [ @$yorg ];                # always make copy to preserve
  1079.  
  1080.   my ($car,$bar,$prd,$dd,$xi,$yi,@q,$v2,$v1,@d,$tmp,$q,$u2,$u1,$u0);
  1081.  
  1082.   $car = $bar = $prd = 0;
  1083.   if (($dd = int($BASE/($y->[-1]+1))) != 1) 
  1084.     {
  1085.     for $xi (@$x) 
  1086.       {
  1087.       $xi = $xi * $dd + $car;
  1088.       $xi -= ($car = int($xi / $BASE)) * $BASE;
  1089.       }
  1090.     push(@$x, $car); $car = 0;
  1091.     for $yi (@$y) 
  1092.       {
  1093.       $yi = $yi * $dd + $car;
  1094.       $yi -= ($car = int($yi / $BASE)) * $BASE;
  1095.       }
  1096.     }
  1097.   else 
  1098.     {
  1099.     push(@$x, 0);
  1100.     }
  1101.  
  1102.   # @q will accumulate the final result, $q contains the current computed
  1103.   # part of the final result
  1104.  
  1105.   @q = (); ($v2,$v1) = @$y[-2,-1];
  1106.   $v2 = 0 unless $v2;
  1107.   while ($#$x > $#$y) 
  1108.     {
  1109.     ($u2,$u1,$u0) = @$x[-3..-1];
  1110.     $u2 = 0 unless $u2;
  1111.     #warn "oups v1 is 0, u0: $u0 $y->[-2] $y->[-1] l ",scalar @$y,"\n"
  1112.     # if $v1 == 0;
  1113.     $q = (($u0 == $v1) ? $MAX_VAL : int(($u0*$BASE+$u1)/$v1));
  1114.     --$q while ($v2*$q > ($u0*$BASE+$u1-$q*$v1)*$BASE+$u2);
  1115.     if ($q)
  1116.       {
  1117.       ($car, $bar) = (0,0);
  1118.       for ($yi = 0, $xi = $#$x-$#$y-1; $yi <= $#$y; ++$yi,++$xi) 
  1119.         {
  1120.         $prd = $q * $y->[$yi] + $car;
  1121.         $prd -= ($car = int($prd / $BASE)) * $BASE;
  1122.     $x->[$xi] += $BASE if ($bar = (($x->[$xi] -= $prd + $bar) < 0));
  1123.     }
  1124.       if ($x->[-1] < $car + $bar) 
  1125.         {
  1126.         $car = 0; --$q;
  1127.     for ($yi = 0, $xi = $#$x-$#$y-1; $yi <= $#$y; ++$yi,++$xi) 
  1128.           {
  1129.       $x->[$xi] -= $BASE
  1130.        if ($car = (($x->[$xi] += $y->[$yi] + $car) >= $BASE));
  1131.       }
  1132.     }   
  1133.       }
  1134.     pop(@$x); unshift(@q, $q);
  1135.     }
  1136.   if (wantarray) 
  1137.     {
  1138.     @d = ();
  1139.     if ($dd != 1)  
  1140.       {
  1141.       $car = 0; 
  1142.       for $xi (reverse @$x) 
  1143.         {
  1144.         $prd = $car * $BASE + $xi;
  1145.         $car = $prd - ($tmp = int($prd / $dd)) * $dd;
  1146.         unshift(@d, $tmp);
  1147.         }
  1148.       }
  1149.     else 
  1150.       {
  1151.       @d = @$x;
  1152.       }
  1153.     @$x = @q;
  1154.     my $d = \@d; 
  1155.     __strip_zeros($x);
  1156.     __strip_zeros($d);
  1157.     return ($x,$d);
  1158.     }
  1159.   @$x = @q;
  1160.   __strip_zeros($x);
  1161.   $x;
  1162.   }
  1163.  
  1164. ##############################################################################
  1165. # testing
  1166.  
  1167. sub _acmp
  1168.   {
  1169.   # internal absolute post-normalized compare (ignore signs)
  1170.   # ref to array, ref to array, return <0, 0, >0
  1171.   # arrays must have at least one entry; this is not checked for
  1172.   my ($c,$cx,$cy) = @_;
  1173.  
  1174.   # shortcut for short numbers 
  1175.   return (($cx->[0] <=> $cy->[0]) <=> 0) 
  1176.    if scalar @$cx == scalar @$cy && scalar @$cx == 1;
  1177.  
  1178.   # fast comp based on number of array elements (aka pseudo-length)
  1179.   my $lxy = (scalar @$cx - scalar @$cy)
  1180.   # or length of first element if same number of elements (aka difference 0)
  1181.     ||
  1182.   # need int() here because sometimes the last element is '00018' vs '18'
  1183.    (length(int($cx->[-1])) - length(int($cy->[-1])));
  1184.   return -1 if $lxy < 0;                # already differs, ret
  1185.   return 1 if $lxy > 0;                    # ditto
  1186.  
  1187.   # manual way (abort if unequal, good for early ne)
  1188.   my $a; my $j = scalar @$cx;
  1189.   while (--$j >= 0)
  1190.     {
  1191.     last if ($a = $cx->[$j] - $cy->[$j]);
  1192.     }
  1193.   $a <=> 0;
  1194.   }
  1195.  
  1196. sub _len
  1197.   {
  1198.   # compute number of digits in base 10
  1199.  
  1200.   # int() because add/sub sometimes leaves strings (like '00005') instead of
  1201.   # '5' in this place, thus causing length() to report wrong length
  1202.   my $cx = $_[1];
  1203.  
  1204.   (@$cx-1)*$BASE_LEN+length(int($cx->[-1]));
  1205.   }
  1206.  
  1207. sub _digit
  1208.   {
  1209.   # return the nth digit, negative values count backward
  1210.   # zero is rightmost, so _digit(123,0) will give 3
  1211.   my ($c,$x,$n) = @_;
  1212.  
  1213.   my $len = _len('',$x);
  1214.  
  1215.   $n = $len+$n if $n < 0;        # -1 last, -2 second-to-last
  1216.   $n = abs($n);                # if negative was too big
  1217.   $len--; $n = $len if $n > $len;    # n to big?
  1218.   
  1219.   my $elem = int($n / $BASE_LEN);    # which array element
  1220.   my $digit = $n % $BASE_LEN;        # which digit in this element
  1221.   $elem = '0' x $BASE_LEN . @$x[$elem];    # get element padded with 0's
  1222.   substr($elem,-$digit-1,1);
  1223.   }
  1224.  
  1225. sub _zeros
  1226.   {
  1227.   # return amount of trailing zeros in decimal
  1228.   # check each array elem in _m for having 0 at end as long as elem == 0
  1229.   # Upon finding a elem != 0, stop
  1230.   my $x = $_[1];
  1231.  
  1232.   return 0 if scalar @$x == 1 && $x->[0] == 0;
  1233.  
  1234.   my $zeros = 0; my $elem;
  1235.   foreach my $e (@$x)
  1236.     {
  1237.     if ($e != 0)
  1238.       {
  1239.       $elem = "$e";                # preserve x
  1240.       $elem =~ s/.*?(0*$)/$1/;            # strip anything not zero
  1241.       $zeros *= $BASE_LEN;            # elems * 5
  1242.       $zeros += length($elem);            # count trailing zeros
  1243.       last;                    # early out
  1244.       }
  1245.     $zeros ++;                    # real else branch: 50% slower!
  1246.     }
  1247.   $zeros;
  1248.   }
  1249.  
  1250. ##############################################################################
  1251. # _is_* routines
  1252.  
  1253. sub _is_zero
  1254.   {
  1255.   # return true if arg is zero 
  1256.   (((scalar @{$_[1]} == 1) && ($_[1]->[0] == 0))) <=> 0;
  1257.   }
  1258.  
  1259. sub _is_even
  1260.   {
  1261.   # return true if arg is even
  1262.   (!($_[1]->[0] & 1)) <=> 0; 
  1263.   }
  1264.  
  1265. sub _is_odd
  1266.   {
  1267.   # return true if arg is even
  1268.   (($_[1]->[0] & 1)) <=> 0; 
  1269.   }
  1270.  
  1271. sub _is_one
  1272.   {
  1273.   # return true if arg is one
  1274.   (scalar @{$_[1]} == 1) && ($_[1]->[0] == 1) <=> 0; 
  1275.   }
  1276.  
  1277. sub _is_two
  1278.   {
  1279.   # return true if arg is two 
  1280.   (scalar @{$_[1]} == 1) && ($_[1]->[0] == 2) <=> 0; 
  1281.   }
  1282.  
  1283. sub _is_ten
  1284.   {
  1285.   # return true if arg is ten 
  1286.   (scalar @{$_[1]} == 1) && ($_[1]->[0] == 10) <=> 0; 
  1287.   }
  1288.  
  1289. sub __strip_zeros
  1290.   {
  1291.   # internal normalization function that strips leading zeros from the array
  1292.   # args: ref to array
  1293.   my $s = shift;
  1294.  
  1295.   my $cnt = scalar @$s; # get count of parts
  1296.   my $i = $cnt-1;
  1297.   push @$s,0 if $i < 0;        # div might return empty results, so fix it
  1298.  
  1299.   return $s if @$s == 1;        # early out
  1300.  
  1301.   #print "strip: cnt $cnt i $i\n";
  1302.   # '0', '3', '4', '0', '0',
  1303.   #  0    1    2    3    4
  1304.   # cnt = 5, i = 4
  1305.   # i = 4
  1306.   # i = 3
  1307.   # => fcnt = cnt - i (5-2 => 3, cnt => 5-1 = 4, throw away from 4th pos)
  1308.   # >= 1: skip first part (this can be zero)
  1309.   while ($i > 0) { last if $s->[$i] != 0; $i--; }
  1310.   $i++; splice @$s,$i if ($i < $cnt); # $i cant be 0
  1311.   $s;                                                                    
  1312.   }                                                                             
  1313.  
  1314. ###############################################################################
  1315. # check routine to test internal state for corruptions
  1316.  
  1317. sub _check
  1318.   {
  1319.   # used by the test suite
  1320.   my $x = $_[1];
  1321.  
  1322.   return "$x is not a reference" if !ref($x);
  1323.  
  1324.   # are all parts are valid?
  1325.   my $i = 0; my $j = scalar @$x; my ($e,$try);
  1326.   while ($i < $j)
  1327.     {
  1328.     $e = $x->[$i]; $e = 'undef' unless defined $e;
  1329.     $try = '=~ /^[\+]?[0-9]+\$/; '."($x, $e)";
  1330.     last if $e !~ /^[+]?[0-9]+$/;
  1331.     $try = '=~ /^[\+]?[0-9]+\$/; '."($x, $e) (stringify)";
  1332.     last if "$e" !~ /^[+]?[0-9]+$/;
  1333.     $try = '=~ /^[\+]?[0-9]+\$/; '."($x, $e) (cat-stringify)";
  1334.     last if '' . "$e" !~ /^[+]?[0-9]+$/;
  1335.     $try = ' < 0 || >= $BASE; '."($x, $e)";
  1336.     last if $e <0 || $e >= $BASE;
  1337.     # this test is disabled, since new/bnorm and certain ops (like early out
  1338.     # in add/sub) are allowed/expected to leave '00000' in some elements
  1339.     #$try = '=~ /^00+/; '."($x, $e)";
  1340.     #last if $e =~ /^00+/;
  1341.     $i++;
  1342.     }
  1343.   return "Illegal part '$e' at pos $i (tested: $try)" if $i < $j;
  1344.   0;
  1345.   }
  1346.  
  1347.  
  1348. ###############################################################################
  1349.  
  1350. sub _mod
  1351.   {
  1352.   # if possible, use mod shortcut
  1353.   my ($c,$x,$yo) = @_;
  1354.  
  1355.   # slow way since $y to big
  1356.   if (scalar @$yo > 1)
  1357.     {
  1358.     my ($xo,$rem) = _div($c,$x,$yo);
  1359.     return $rem;
  1360.     }
  1361.  
  1362.   my $y = $yo->[0];
  1363.   # both are single element arrays
  1364.   if (scalar @$x == 1)
  1365.     {
  1366.     $x->[0] %= $y;
  1367.     return $x;
  1368.     }
  1369.  
  1370.   # @y is a single element, but @x has more than one element
  1371.   my $b = $BASE % $y;
  1372.   if ($b == 0)
  1373.     {
  1374.     # when BASE % Y == 0 then (B * BASE) % Y == 0
  1375.     # (B * BASE) % $y + A % Y => A % Y
  1376.     # so need to consider only last element: O(1)
  1377.     $x->[0] %= $y;
  1378.     }
  1379.   elsif ($b == 1)
  1380.     {
  1381.     # else need to go through all elements: O(N), but loop is a bit simplified
  1382.     my $r = 0;
  1383.     foreach (@$x)
  1384.       {
  1385.       $r = ($r + $_) % $y;        # not much faster, but heh...
  1386.       #$r += $_ % $y; $r %= $y;
  1387.       }
  1388.     $r = 0 if $r == $y;
  1389.     $x->[0] = $r;
  1390.     }
  1391.   else
  1392.     {
  1393.     # else need to go through all elements: O(N)
  1394.     my $r = 0; my $bm = 1;
  1395.     foreach (@$x)
  1396.       {
  1397.       $r = ($_ * $bm + $r) % $y;
  1398.       $bm = ($bm * $b) % $y;
  1399.  
  1400.       #$r += ($_ % $y) * $bm;
  1401.       #$bm *= $b;
  1402.       #$bm %= $y;
  1403.       #$r %= $y;
  1404.       }
  1405.     $r = 0 if $r == $y;
  1406.     $x->[0] = $r;
  1407.     }
  1408.   splice (@$x,1);        # keep one element of $x
  1409.   $x;
  1410.   }
  1411.  
  1412. ##############################################################################
  1413. # shifts
  1414.  
  1415. sub _rsft
  1416.   {
  1417.   my ($c,$x,$y,$n) = @_;
  1418.  
  1419.   if ($n != 10)
  1420.     {
  1421.     $n = _new($c,$n); return _div($c,$x, _pow($c,$n,$y));
  1422.     }
  1423.  
  1424.   # shortcut (faster) for shifting by 10)
  1425.   # multiples of $BASE_LEN
  1426.   my $dst = 0;                # destination
  1427.   my $src = _num($c,$y);        # as normal int
  1428.   my $xlen = (@$x-1)*$BASE_LEN+length(int($x->[-1]));  # len of x in digits
  1429.   if ($src >= $xlen or ($src == $xlen and ! defined $x->[1]))
  1430.     {
  1431.     # 12345 67890 shifted right by more than 10 digits => 0
  1432.     splice (@$x,1);                    # leave only one element
  1433.     $x->[0] = 0;                       # set to zero
  1434.     return $x;
  1435.     }
  1436.   my $rem = $src % $BASE_LEN;        # remainder to shift
  1437.   $src = int($src / $BASE_LEN);        # source
  1438.   if ($rem == 0)
  1439.     {
  1440.     splice (@$x,0,$src);        # even faster, 38.4 => 39.3
  1441.     }
  1442.   else
  1443.     {
  1444.     my $len = scalar @$x - $src;    # elems to go
  1445.     my $vd; my $z = '0'x $BASE_LEN;
  1446.     $x->[scalar @$x] = 0;        # avoid || 0 test inside loop
  1447.     while ($dst < $len)
  1448.       {
  1449.       $vd = $z.$x->[$src];
  1450.       $vd = substr($vd,-$BASE_LEN,$BASE_LEN-$rem);
  1451.       $src++;
  1452.       $vd = substr($z.$x->[$src],-$rem,$rem) . $vd;
  1453.       $vd = substr($vd,-$BASE_LEN,$BASE_LEN) if length($vd) > $BASE_LEN;
  1454.       $x->[$dst] = int($vd);
  1455.       $dst++;
  1456.       }
  1457.     splice (@$x,$dst) if $dst > 0;        # kill left-over array elems
  1458.     pop @$x if $x->[-1] == 0 && @$x > 1;    # kill last element if 0
  1459.     } # else rem == 0
  1460.   $x;
  1461.   }
  1462.  
  1463. sub _lsft
  1464.   {
  1465.   my ($c,$x,$y,$n) = @_;
  1466.  
  1467.   if ($n != 10)
  1468.     {
  1469.     $n = _new($c,$n); return _mul($c,$x, _pow($c,$n,$y));
  1470.     }
  1471.  
  1472.   # shortcut (faster) for shifting by 10) since we are in base 10eX
  1473.   # multiples of $BASE_LEN:
  1474.   my $src = scalar @$x;            # source
  1475.   my $len = _num($c,$y);        # shift-len as normal int
  1476.   my $rem = $len % $BASE_LEN;        # remainder to shift
  1477.   my $dst = $src + int($len/$BASE_LEN);    # destination
  1478.   my $vd;                # further speedup
  1479.   $x->[$src] = 0;            # avoid first ||0 for speed
  1480.   my $z = '0' x $BASE_LEN;
  1481.   while ($src >= 0)
  1482.     {
  1483.     $vd = $x->[$src]; $vd = $z.$vd;
  1484.     $vd = substr($vd,-$BASE_LEN+$rem,$BASE_LEN-$rem);
  1485.     $vd .= $src > 0 ? substr($z.$x->[$src-1],-$BASE_LEN,$rem) : '0' x $rem;
  1486.     $vd = substr($vd,-$BASE_LEN,$BASE_LEN) if length($vd) > $BASE_LEN;
  1487.     $x->[$dst] = int($vd);
  1488.     $dst--; $src--;
  1489.     }
  1490.   # set lowest parts to 0
  1491.   while ($dst >= 0) { $x->[$dst--] = 0; }
  1492.   # fix spurios last zero element
  1493.   splice @$x,-1 if $x->[-1] == 0;
  1494.   $x;
  1495.   }
  1496.  
  1497. sub _pow
  1498.   {
  1499.   # power of $x to $y
  1500.   # ref to array, ref to array, return ref to array
  1501.   my ($c,$cx,$cy) = @_;
  1502.  
  1503.   if (scalar @$cy == 1 && $cy->[0] == 0)
  1504.     {
  1505.     splice (@$cx,1); $cx->[0] = 1;        # y == 0 => x => 1
  1506.     return $cx;
  1507.     }
  1508.   if ((scalar @$cx == 1 && $cx->[0] == 1) ||    #    x == 1
  1509.       (scalar @$cy == 1 && $cy->[0] == 1))    # or y == 1
  1510.     {
  1511.     return $cx;
  1512.     }
  1513.   if (scalar @$cx == 1 && $cx->[0] == 0)
  1514.     {
  1515.     splice (@$cx,1); $cx->[0] = 0;        # 0 ** y => 0 (if not y <= 0)
  1516.     return $cx;
  1517.     }
  1518.  
  1519.   my $pow2 = _one();
  1520.  
  1521.   my $y_bin = _as_bin($c,$cy); $y_bin =~ s/^0b//;
  1522.   my $len = length($y_bin);
  1523.   while (--$len > 0)
  1524.     {
  1525.     _mul($c,$pow2,$cx) if substr($y_bin,$len,1) eq '1';        # is odd?
  1526.     _mul($c,$cx,$cx);
  1527.     }
  1528.  
  1529.   _mul($c,$cx,$pow2);
  1530.   $cx;
  1531.   }
  1532.  
  1533. sub _nok
  1534.   {
  1535.   # n over k
  1536.   # ref to array, return ref to array
  1537.   my ($c,$n,$k) = @_;
  1538.  
  1539.   # ( 7 )    7!          7*6*5 * 4*3*2*1   7 * 6 * 5
  1540.   # ( - ) = --------- =  --------------- = ---------
  1541.   # ( 3 )   3! (7-3)!    3*2*1 * 4*3*2*1   3 * 2 * 1 
  1542.  
  1543.   # compute n - k + 2 (so we start with 5 in the example above)
  1544.   my $x = _copy($c,$n);
  1545.  
  1546.   _sub($c,$n,$k);
  1547.   if (!_is_one($c,$n))
  1548.     {
  1549.     _inc($c,$n);
  1550.     my $f = _copy($c,$n); _inc($c,$f);        # n = 5, f = 6, d = 2
  1551.     my $d = _two($c);
  1552.     while (_acmp($c,$f,$x) <= 0)        # f < n ?
  1553.       {
  1554.       # n = (n * f / d) == 5 * 6 / 2 => n == 3
  1555.       $n = _mul($c,$n,$f); $n = _div($c,$n,$d);
  1556.       # f = 7, d = 3
  1557.       _inc($c,$f); _inc($c,$d);
  1558.       }
  1559.     }
  1560.   else 
  1561.     {
  1562.     # keep ref to $n and set it to 1
  1563.     splice (@$n,1); $n->[0] = 1;
  1564.     }
  1565.   $n;
  1566.   }
  1567.  
  1568. my @factorials = (
  1569.   1,
  1570.   1,
  1571.   2,
  1572.   2*3,
  1573.   2*3*4,
  1574.   2*3*4*5,
  1575.   2*3*4*5*6,
  1576.   2*3*4*5*6*7,
  1577. );
  1578.  
  1579. sub _fac
  1580.   {
  1581.   # factorial of $x
  1582.   # ref to array, return ref to array
  1583.   my ($c,$cx) = @_;
  1584.  
  1585.   if ((@$cx == 1) && ($cx->[0] <= 7))
  1586.     {
  1587.     $cx->[0] = $factorials[$cx->[0]];        # 0 => 1, 1 => 1, 2 => 2 etc.
  1588.     return $cx;
  1589.     }
  1590.  
  1591.   if ((@$cx == 1) &&         # we do this only if $x >= 12 and $x <= 7000
  1592.       ($cx->[0] >= 12 && $cx->[0] < 7000))
  1593.     {
  1594.  
  1595.   # Calculate (k-j) * (k-j+1) ... k .. (k+j-1) * (k + j)
  1596.   # See http://blogten.blogspot.com/2007/01/calculating-n.html
  1597.   # The above series can be expressed as factors:
  1598.   #   k * k - (j - i) * 2
  1599.   # We cache k*k, and calculate (j * j) as the sum of the first j odd integers
  1600.  
  1601.   # This will not work when N exceeds the storage of a Perl scalar, however,
  1602.   # in this case the algorithm would be way to slow to terminate, anyway.
  1603.  
  1604.   # As soon as the last element of $cx is 0, we split it up and remember
  1605.   # how many zeors we got so far. The reason is that n! will accumulate
  1606.   # zeros at the end rather fast.
  1607.   my $zero_elements = 0;
  1608.  
  1609.   # If n is even, set n = n -1
  1610.   my $k = _num($c,$cx); my $even = 1;
  1611.   if (($k & 1) == 0)
  1612.     {
  1613.     $even = $k; $k --;
  1614.     }
  1615.   # set k to the center point
  1616.   $k = ($k + 1) / 2;
  1617. #  print "k $k even: $even\n";
  1618.   # now calculate k * k
  1619.   my $k2 = $k * $k;
  1620.   my $odd = 1; my $sum = 1;
  1621.   my $i = $k - 1;
  1622.   # keep reference to x
  1623.   my $new_x = _new($c, $k * $even);
  1624.   @$cx = @$new_x;
  1625.   if ($cx->[0] == 0)
  1626.     {
  1627.     $zero_elements ++; shift @$cx;
  1628.     }
  1629. #  print STDERR "x = ", _str($c,$cx),"\n";
  1630.   my $BASE2 = int(sqrt($BASE))-1;
  1631.   my $j = 1; 
  1632.   while ($j <= $i)
  1633.     {
  1634.     my $m = ($k2 - $sum); $odd += 2; $sum += $odd; $j++;
  1635.     while ($j <= $i && ($m < $BASE2) && (($k2 - $sum) < $BASE2))
  1636.       {
  1637.       $m *= ($k2 - $sum);
  1638.       $odd += 2; $sum += $odd; $j++;
  1639. #      print STDERR "\n k2 $k2 m $m sum $sum odd $odd\n"; sleep(1);
  1640.       }
  1641.     if ($m < $BASE)
  1642.       {
  1643.       _mul($c,$cx,[$m]);
  1644.       }
  1645.     else
  1646.       {
  1647.       _mul($c,$cx,$c->_new($m));
  1648.       }
  1649.     if ($cx->[0] == 0)
  1650.       {
  1651.       $zero_elements ++; shift @$cx;
  1652.       }
  1653. #    print STDERR "Calculate $k2 - $sum = $m (x = ", _str($c,$cx),")\n";
  1654.     }
  1655.   # multiply in the zeros again
  1656.   unshift @$cx, (0) x $zero_elements; 
  1657.   return $cx;
  1658.   }
  1659.  
  1660.   # go forward until $base is exceeded
  1661.   # limit is either $x steps (steps == 100 means a result always too high) or
  1662.   # $base.
  1663.   my $steps = 100; $steps = $cx->[0] if @$cx == 1;
  1664.   my $r = 2; my $cf = 3; my $step = 2; my $last = $r;
  1665.   while ($r*$cf < $BASE && $step < $steps)
  1666.     {
  1667.     $last = $r; $r *= $cf++; $step++;
  1668.     }
  1669.   if ((@$cx == 1) && $step == $cx->[0])
  1670.     {
  1671.     # completely done, so keep reference to $x and return
  1672.     $cx->[0] = $r;
  1673.     return $cx;
  1674.     }
  1675.   
  1676.   # now we must do the left over steps
  1677.   my $n;                    # steps still to do
  1678.   if (scalar @$cx == 1)
  1679.     {
  1680.     $n = $cx->[0];
  1681.     }
  1682.   else
  1683.     {
  1684.     $n = _copy($c,$cx);
  1685.     }
  1686.  
  1687.   # Set $cx to the last result below $BASE (but keep ref to $x)
  1688.   $cx->[0] = $last; splice (@$cx,1);
  1689.   # As soon as the last element of $cx is 0, we split it up and remember
  1690.   # how many zeors we got so far. The reason is that n! will accumulate
  1691.   # zeros at the end rather fast.
  1692.   my $zero_elements = 0;
  1693.  
  1694.   # do left-over steps fit into a scalar?
  1695.   if (ref $n eq 'ARRAY')
  1696.     {
  1697.     # No, so use slower inc() & cmp()
  1698.     # ($n is at least $BASE here)
  1699.     my $base_2 = int(sqrt($BASE)) - 1;
  1700.     #print STDERR "base_2: $base_2\n"; 
  1701.     while ($step < $base_2)
  1702.       {
  1703.       if ($cx->[0] == 0)
  1704.         {
  1705.         $zero_elements ++; shift @$cx;
  1706.         }
  1707.       my $b = $step * ($step + 1); $step += 2;
  1708.       _mul($c,$cx,[$b]);
  1709.       }
  1710.     $step = [$step];
  1711.     while (_acmp($c,$step,$n) <= 0)
  1712.       {
  1713.       if ($cx->[0] == 0)
  1714.         {
  1715.         $zero_elements ++; shift @$cx;
  1716.         }
  1717.       _mul($c,$cx,$step); _inc($c,$step);
  1718.       }
  1719.     }
  1720.   else
  1721.     {
  1722.     # Yes, so we can speed it up slightly
  1723.   
  1724. #    print "# left over steps $n\n";
  1725.  
  1726.     my $base_4 = int(sqrt(sqrt($BASE))) - 2;
  1727.     #print STDERR "base_4: $base_4\n";
  1728.     my $n4 = $n - 4; 
  1729.     while ($step < $n4 && $step < $base_4)
  1730.       {
  1731.       if ($cx->[0] == 0)
  1732.         {
  1733.         $zero_elements ++; shift @$cx;
  1734.         }
  1735.       my $b = $step * ($step + 1); $step += 2; $b *= $step * ($step + 1); $step += 2;
  1736.       _mul($c,$cx,[$b]);
  1737.       }
  1738.     my $base_2 = int(sqrt($BASE)) - 1;
  1739.     my $n2 = $n - 2; 
  1740.     #print STDERR "base_2: $base_2\n"; 
  1741.     while ($step < $n2 && $step < $base_2)
  1742.       {
  1743.       if ($cx->[0] == 0)
  1744.         {
  1745.         $zero_elements ++; shift @$cx;
  1746.         }
  1747.       my $b = $step * ($step + 1); $step += 2;
  1748.       _mul($c,$cx,[$b]);
  1749.       }
  1750.     # do what's left over
  1751.     while ($step <= $n)
  1752.       {
  1753.       _mul($c,$cx,[$step]); $step++;
  1754.       if ($cx->[0] == 0)
  1755.         {
  1756.         $zero_elements ++; shift @$cx;
  1757.         }
  1758.       }
  1759.     }
  1760.   # multiply in the zeros again
  1761.   unshift @$cx, (0) x $zero_elements;
  1762.   $cx;            # return result
  1763.   }
  1764.  
  1765. #############################################################################
  1766.  
  1767. sub _log_int
  1768.   {
  1769.   # calculate integer log of $x to base $base
  1770.   # ref to array, ref to array - return ref to array
  1771.   my ($c,$x,$base) = @_;
  1772.  
  1773.   # X == 0 => NaN
  1774.   return if (scalar @$x == 1 && $x->[0] == 0);
  1775.   # BASE 0 or 1 => NaN
  1776.   return if (scalar @$base == 1 && $base->[0] < 2);
  1777.   my $cmp = _acmp($c,$x,$base); # X == BASE => 1
  1778.   if ($cmp == 0)
  1779.     {
  1780.     splice (@$x,1); $x->[0] = 1;
  1781.     return ($x,1)
  1782.     }
  1783.   # X < BASE
  1784.   if ($cmp < 0)
  1785.     {
  1786.     splice (@$x,1); $x->[0] = 0;
  1787.     return ($x,undef);
  1788.     }
  1789.  
  1790.   my $x_org = _copy($c,$x);        # preserve x
  1791.   splice(@$x,1); $x->[0] = 1;        # keep ref to $x
  1792.  
  1793.   # Compute a guess for the result based on:
  1794.   # $guess = int ( length_in_base_10(X) / ( log(base) / log(10) ) )
  1795.   my $len = _len($c,$x_org);
  1796.   my $log = log($base->[-1]) / log(10);
  1797.  
  1798.   # for each additional element in $base, we add $BASE_LEN to the result,
  1799.   # based on the observation that log($BASE,10) is BASE_LEN and
  1800.   # log(x*y) == log(x) + log(y):
  1801.   $log += ((scalar @$base)-1) * $BASE_LEN;
  1802.  
  1803.   # calculate now a guess based on the values obtained above:
  1804.   my $res = int($len / $log);
  1805.  
  1806.   $x->[0] = $res;
  1807.   my $trial = _pow ($c, _copy($c, $base), $x);
  1808.   my $a = _acmp($c,$trial,$x_org);
  1809.  
  1810. #  print STDERR "# trial ", _str($c,$x)," was: $a (0 = exact, -1 too small, +1 too big)\n";
  1811.  
  1812.   # found an exact result?
  1813.   return ($x,1) if $a == 0;
  1814.  
  1815.   if ($a > 0)
  1816.     {
  1817.     # or too big
  1818.     _div($c,$trial,$base); _dec($c, $x);
  1819.     while (($a = _acmp($c,$trial,$x_org)) > 0)
  1820.       {
  1821. #      print STDERR "# big _log_int at ", _str($c,$x), "\n"; 
  1822.       _div($c,$trial,$base); _dec($c, $x);
  1823.       }
  1824.     # result is now exact (a == 0), or too small (a < 0)
  1825.     return ($x, $a == 0 ? 1 : 0);
  1826.     }
  1827.  
  1828.   # else: result was to small
  1829.   _mul($c,$trial,$base);
  1830.  
  1831.   # did we now get the right result?
  1832.   $a = _acmp($c,$trial,$x_org);
  1833.  
  1834.   if ($a == 0)                # yes, exactly
  1835.     {
  1836.     _inc($c, $x);
  1837.     return ($x,1); 
  1838.     }
  1839.   return ($x,0) if $a > 0;  
  1840.  
  1841.   # Result still too small (we should come here only if the estimate above
  1842.   # was very off base):
  1843.  
  1844.   # Now let the normal trial run obtain the real result
  1845.   # Simple loop that increments $x by 2 in each step, possible overstepping
  1846.   # the real result
  1847.  
  1848.   my $base_mul = _mul($c, _copy($c,$base), $base);    # $base * $base
  1849.  
  1850.   while (($a = _acmp($c,$trial,$x_org)) < 0)
  1851.     {
  1852. #    print STDERR "# small _log_int at ", _str($c,$x), "\n"; 
  1853.     _mul($c,$trial,$base_mul); _add($c, $x, [2]);
  1854.     }
  1855.  
  1856.   my $exact = 1;
  1857.   if ($a > 0)
  1858.     {
  1859.     # overstepped the result
  1860.     _dec($c, $x);
  1861.     _div($c,$trial,$base);
  1862.     $a = _acmp($c,$trial,$x_org);
  1863.     if ($a > 0)
  1864.       {
  1865.       _dec($c, $x);
  1866.       }
  1867.     $exact = 0 if $a != 0;        # a = -1 => not exact result, a = 0 => exact
  1868.     }
  1869.   
  1870.   ($x,$exact);                # return result
  1871.   }
  1872.  
  1873. # for debugging:
  1874.   use constant DEBUG => 0;
  1875.   my $steps = 0;
  1876.   sub steps { $steps };
  1877.  
  1878. sub _sqrt
  1879.   {
  1880.   # square-root of $x in place
  1881.   # Compute a guess of the result (by rule of thumb), then improve it via
  1882.   # Newton's method.
  1883.   my ($c,$x) = @_;
  1884.  
  1885.   if (scalar @$x == 1)
  1886.     {
  1887.     # fits into one Perl scalar, so result can be computed directly
  1888.     $x->[0] = int(sqrt($x->[0]));
  1889.     return $x;
  1890.     } 
  1891.   my $y = _copy($c,$x);
  1892.   # hopefully _len/2 is < $BASE, the -1 is to always undershot the guess
  1893.   # since our guess will "grow"
  1894.   my $l = int((_len($c,$x)-1) / 2);    
  1895.  
  1896.   my $lastelem = $x->[-1];                    # for guess
  1897.   my $elems = scalar @$x - 1;
  1898.   # not enough digits, but could have more?
  1899.   if ((length($lastelem) <= 3) && ($elems > 1))
  1900.     {
  1901.     # right-align with zero pad
  1902.     my $len = length($lastelem) & 1;
  1903.     print "$lastelem => " if DEBUG;
  1904.     $lastelem .= substr($x->[-2] . '0' x $BASE_LEN,0,$BASE_LEN);
  1905.     # former odd => make odd again, or former even to even again
  1906.     $lastelem = $lastelem / 10 if (length($lastelem) & 1) != $len;
  1907.     print "$lastelem\n" if DEBUG;
  1908.     }
  1909.  
  1910.   # construct $x (instead of _lsft($c,$x,$l,10)
  1911.   my $r = $l % $BASE_LEN;    # 10000 00000 00000 00000 ($BASE_LEN=5)
  1912.   $l = int($l / $BASE_LEN);
  1913.   print "l =  $l " if DEBUG;
  1914.  
  1915.   splice @$x,$l;        # keep ref($x), but modify it
  1916.  
  1917.   # we make the first part of the guess not '1000...0' but int(sqrt($lastelem))
  1918.   # that gives us:
  1919.   # 14400 00000 => sqrt(14400) => guess first digits to be 120
  1920.   # 144000 000000 => sqrt(144000) => guess 379
  1921.  
  1922.   print "$lastelem (elems $elems) => " if DEBUG;
  1923.   $lastelem = $lastelem / 10 if ($elems & 1 == 1);        # odd or even?
  1924.   my $g = sqrt($lastelem); $g =~ s/\.//;            # 2.345 => 2345
  1925.   $r -= 1 if $elems & 1 == 0;                    # 70 => 7
  1926.  
  1927.   # padd with zeros if result is too short
  1928.   $x->[$l--] = int(substr($g . '0' x $r,0,$r+1));
  1929.   print "now ",$x->[-1] if DEBUG;
  1930.   print " would have been ", int('1' . '0' x $r),"\n" if DEBUG;
  1931.  
  1932.   # If @$x > 1, we could compute the second elem of the guess, too, to create
  1933.   # an even better guess. Not implemented yet. Does it improve performance?
  1934.   $x->[$l--] = 0 while ($l >= 0);    # all other digits of guess are zero
  1935.  
  1936.   print "start x= ",_str($c,$x),"\n" if DEBUG;
  1937.   my $two = _two();
  1938.   my $last = _zero();
  1939.   my $lastlast = _zero();
  1940.   $steps = 0 if DEBUG;
  1941.   while (_acmp($c,$last,$x) != 0 && _acmp($c,$lastlast,$x) != 0)
  1942.     {
  1943.     $steps++ if DEBUG;
  1944.     $lastlast = _copy($c,$last);
  1945.     $last = _copy($c,$x);
  1946.     _add($c,$x, _div($c,_copy($c,$y),$x));
  1947.     _div($c,$x, $two );
  1948.     print " x= ",_str($c,$x),"\n" if DEBUG;
  1949.     }
  1950.   print "\nsteps in sqrt: $steps, " if DEBUG;
  1951.   _dec($c,$x) if _acmp($c,$y,_mul($c,_copy($c,$x),$x)) < 0;    # overshot? 
  1952.   print " final ",$x->[-1],"\n" if DEBUG;
  1953.   $x;
  1954.   }
  1955.  
  1956. sub _root
  1957.   {
  1958.   # take n'th root of $x in place (n >= 3)
  1959.   my ($c,$x,$n) = @_;
  1960.  
  1961.   if (scalar @$x == 1)
  1962.     {
  1963.     if (scalar @$n > 1)
  1964.       {
  1965.       # result will always be smaller than 2 so trunc to 1 at once
  1966.       $x->[0] = 1;
  1967.       }
  1968.     else
  1969.       {
  1970.       # fits into one Perl scalar, so result can be computed directly
  1971.       # cannot use int() here, because it rounds wrongly (try 
  1972.       # (81 ** 3) ** (1/3) to see what I mean)
  1973.       #$x->[0] = int( $x->[0] ** (1 / $n->[0]) );
  1974.       # round to 8 digits, then truncate result to integer
  1975.       $x->[0] = int ( sprintf ("%.8f", $x->[0] ** (1 / $n->[0]) ) );
  1976.       }
  1977.     return $x;
  1978.     } 
  1979.  
  1980.   # we know now that X is more than one element long
  1981.  
  1982.   # if $n is a power of two, we can repeatedly take sqrt($X) and find the
  1983.   # proper result, because sqrt(sqrt($x)) == root($x,4)
  1984.   my $b = _as_bin($c,$n);
  1985.   if ($b =~ /0b1(0+)$/)
  1986.     {
  1987.     my $count = CORE::length($1);    # 0b100 => len('00') => 2
  1988.     my $cnt = $count;            # counter for loop
  1989.     unshift (@$x, 0);            # add one element, together with one
  1990.                     # more below in the loop this makes 2
  1991.     while ($cnt-- > 0)
  1992.       {
  1993.       # 'inflate' $X by adding one element, basically computing
  1994.       # $x * $BASE * $BASE. This gives us more $BASE_LEN digits for result
  1995.       # since len(sqrt($X)) approx == len($x) / 2.
  1996.       unshift (@$x, 0);
  1997.       # calculate sqrt($x), $x is now one element to big, again. In the next
  1998.       # round we make that two, again.
  1999.       _sqrt($c,$x);
  2000.       }
  2001.     # $x is now one element to big, so truncate result by removing it
  2002.     splice (@$x,0,1);
  2003.     } 
  2004.   else
  2005.     {
  2006.     # trial computation by starting with 2,4,8,16 etc until we overstep
  2007.     my $step;
  2008.     my $trial = _two();
  2009.  
  2010.     # while still to do more than X steps
  2011.     do
  2012.       {
  2013.       $step = _two();
  2014.       while (_acmp($c, _pow($c, _copy($c, $trial), $n), $x) < 0)
  2015.         {
  2016.         _mul ($c, $step, [2]);
  2017.         _add ($c, $trial, $step);
  2018.         }
  2019.  
  2020.       # hit exactly?
  2021.       if (_acmp($c, _pow($c, _copy($c, $trial), $n), $x) == 0)
  2022.         {
  2023.         @$x = @$trial;            # make copy while preserving ref to $x
  2024.         return $x;
  2025.         }
  2026.       # overstepped, so go back on step
  2027.       _sub($c, $trial, $step);
  2028.       } while (scalar @$step > 1 || $step->[0] > 128);
  2029.  
  2030.     # reset step to 2
  2031.     $step = _two();
  2032.     # add two, because $trial cannot be exactly the result (otherwise we would
  2033.     # alrady have found it)
  2034.     _add($c, $trial, $step);
  2035.  
  2036.     # and now add more and more (2,4,6,8,10 etc)
  2037.     while (_acmp($c, _pow($c, _copy($c, $trial), $n), $x) < 0)
  2038.       {
  2039.       _add ($c, $trial, $step);
  2040.       }
  2041.  
  2042.     # hit not exactly? (overstepped)
  2043.     if (_acmp($c, _pow($c, _copy($c, $trial), $n), $x) > 0)
  2044.       {
  2045.       _dec($c,$trial);
  2046.       }
  2047.  
  2048.     # hit not exactly? (overstepped)
  2049.     # 80 too small, 81 slightly too big, 82 too big
  2050.     if (_acmp($c, _pow($c, _copy($c, $trial), $n), $x) > 0)
  2051.       {
  2052.       _dec ($c, $trial); 
  2053.       }
  2054.  
  2055.     @$x = @$trial;            # make copy while preserving ref to $x
  2056.     return $x;
  2057.     }
  2058.   $x; 
  2059.   }
  2060.  
  2061. ##############################################################################
  2062. # binary stuff
  2063.  
  2064. sub _and
  2065.   {
  2066.   my ($c,$x,$y) = @_;
  2067.  
  2068.   # the shortcut makes equal, large numbers _really_ fast, and makes only a
  2069.   # very small performance drop for small numbers (e.g. something with less
  2070.   # than 32 bit) Since we optimize for large numbers, this is enabled.
  2071.   return $x if _acmp($c,$x,$y) == 0;        # shortcut
  2072.   
  2073.   my $m = _one(); my ($xr,$yr);
  2074.   my $mask = $AND_MASK;
  2075.  
  2076.   my $x1 = $x;
  2077.   my $y1 = _copy($c,$y);            # make copy
  2078.   $x = _zero();
  2079.   my ($b,$xrr,$yrr);
  2080.   use integer;
  2081.   while (!_is_zero($c,$x1) && !_is_zero($c,$y1))
  2082.     {
  2083.     ($x1, $xr) = _div($c,$x1,$mask);
  2084.     ($y1, $yr) = _div($c,$y1,$mask);
  2085.  
  2086.     # make ints() from $xr, $yr
  2087.     # this is when the AND_BITS are greater than $BASE and is slower for
  2088.     # small (<256 bits) numbers, but faster for large numbers. Disabled
  2089.     # due to KISS principle
  2090.  
  2091. #    $b = 1; $xrr = 0; foreach (@$xr) { $xrr += $_ * $b; $b *= $BASE; }
  2092. #    $b = 1; $yrr = 0; foreach (@$yr) { $yrr += $_ * $b; $b *= $BASE; }
  2093. #    _add($c,$x, _mul($c, _new( $c, ($xrr & $yrr) ), $m) );
  2094.     
  2095.     # 0+ due to '&' doesn't work in strings
  2096.     _add($c,$x, _mul($c, [ 0+$xr->[0] & 0+$yr->[0] ], $m) );
  2097.     _mul($c,$m,$mask);
  2098.     }
  2099.   $x;
  2100.   }
  2101.  
  2102. sub _xor
  2103.   {
  2104.   my ($c,$x,$y) = @_;
  2105.  
  2106.   return _zero() if _acmp($c,$x,$y) == 0;    # shortcut (see -and)
  2107.  
  2108.   my $m = _one(); my ($xr,$yr);
  2109.   my $mask = $XOR_MASK;
  2110.  
  2111.   my $x1 = $x;
  2112.   my $y1 = _copy($c,$y);            # make copy
  2113.   $x = _zero();
  2114.   my ($b,$xrr,$yrr);
  2115.   use integer;
  2116.   while (!_is_zero($c,$x1) && !_is_zero($c,$y1))
  2117.     {
  2118.     ($x1, $xr) = _div($c,$x1,$mask);
  2119.     ($y1, $yr) = _div($c,$y1,$mask);
  2120.     # make ints() from $xr, $yr (see _and())
  2121.     #$b = 1; $xrr = 0; foreach (@$xr) { $xrr += $_ * $b; $b *= $BASE; }
  2122.     #$b = 1; $yrr = 0; foreach (@$yr) { $yrr += $_ * $b; $b *= $BASE; }
  2123.     #_add($c,$x, _mul($c, _new( $c, ($xrr ^ $yrr) ), $m) );
  2124.  
  2125.     # 0+ due to '^' doesn't work in strings
  2126.     _add($c,$x, _mul($c, [ 0+$xr->[0] ^ 0+$yr->[0] ], $m) );
  2127.     _mul($c,$m,$mask);
  2128.     }
  2129.   # the loop stops when the shorter of the two numbers is exhausted
  2130.   # the remainder of the longer one will survive bit-by-bit, so we simple
  2131.   # multiply-add it in
  2132.   _add($c,$x, _mul($c, $x1, $m) ) if !_is_zero($c,$x1);
  2133.   _add($c,$x, _mul($c, $y1, $m) ) if !_is_zero($c,$y1);
  2134.   
  2135.   $x;
  2136.   }
  2137.  
  2138. sub _or
  2139.   {
  2140.   my ($c,$x,$y) = @_;
  2141.  
  2142.   return $x if _acmp($c,$x,$y) == 0;        # shortcut (see _and)
  2143.  
  2144.   my $m = _one(); my ($xr,$yr);
  2145.   my $mask = $OR_MASK;
  2146.  
  2147.   my $x1 = $x;
  2148.   my $y1 = _copy($c,$y);            # make copy
  2149.   $x = _zero();
  2150.   my ($b,$xrr,$yrr);
  2151.   use integer;
  2152.   while (!_is_zero($c,$x1) && !_is_zero($c,$y1))
  2153.     {
  2154.     ($x1, $xr) = _div($c,$x1,$mask);
  2155.     ($y1, $yr) = _div($c,$y1,$mask);
  2156.     # make ints() from $xr, $yr (see _and())
  2157. #    $b = 1; $xrr = 0; foreach (@$xr) { $xrr += $_ * $b; $b *= $BASE; }
  2158. #    $b = 1; $yrr = 0; foreach (@$yr) { $yrr += $_ * $b; $b *= $BASE; }
  2159. #    _add($c,$x, _mul($c, _new( $c, ($xrr | $yrr) ), $m) );
  2160.     
  2161.     # 0+ due to '|' doesn't work in strings
  2162.     _add($c,$x, _mul($c, [ 0+$xr->[0] | 0+$yr->[0] ], $m) );
  2163.     _mul($c,$m,$mask);
  2164.     }
  2165.   # the loop stops when the shorter of the two numbers is exhausted
  2166.   # the remainder of the longer one will survive bit-by-bit, so we simple
  2167.   # multiply-add it in
  2168.   _add($c,$x, _mul($c, $x1, $m) ) if !_is_zero($c,$x1);
  2169.   _add($c,$x, _mul($c, $y1, $m) ) if !_is_zero($c,$y1);
  2170.   
  2171.   $x;
  2172.   }
  2173.  
  2174. sub _as_hex
  2175.   {
  2176.   # convert a decimal number to hex (ref to array, return ref to string)
  2177.   my ($c,$x) = @_;
  2178.  
  2179.   # fits into one element (handle also 0x0 case)
  2180.   return sprintf("0x%x",$x->[0]) if @$x == 1;
  2181.  
  2182.   my $x1 = _copy($c,$x);
  2183.  
  2184.   my $es = '';
  2185.   my ($xr, $h, $x10000);
  2186.   if ($] >= 5.006)
  2187.     {
  2188.     $x10000 = [ 0x10000 ]; $h = 'h4';
  2189.     }
  2190.   else
  2191.     {
  2192.     $x10000 = [ 0x1000 ]; $h = 'h3';
  2193.     }
  2194.   while (@$x1 != 1 || $x1->[0] != 0)        # _is_zero()
  2195.     {
  2196.     ($x1, $xr) = _div($c,$x1,$x10000);
  2197.     $es .= unpack($h,pack('V',$xr->[0]));
  2198.     }
  2199.   $es = reverse $es;
  2200.   $es =~ s/^[0]+//;   # strip leading zeros
  2201.   '0x' . $es;                    # return result prepended with 0x
  2202.   }
  2203.  
  2204. sub _as_bin
  2205.   {
  2206.   # convert a decimal number to bin (ref to array, return ref to string)
  2207.   my ($c,$x) = @_;
  2208.  
  2209.   # fits into one element (and Perl recent enough), handle also 0b0 case
  2210.   # handle zero case for older Perls
  2211.   if ($] <= 5.005 && @$x == 1 && $x->[0] == 0)
  2212.     {
  2213.     my $t = '0b0'; return $t;
  2214.     }
  2215.   if (@$x == 1 && $] >= 5.006)
  2216.     {
  2217.     my $t = sprintf("0b%b",$x->[0]);
  2218.     return $t;
  2219.     }
  2220.   my $x1 = _copy($c,$x);
  2221.  
  2222.   my $es = '';
  2223.   my ($xr, $b, $x10000);
  2224.   if ($] >= 5.006)
  2225.     {
  2226.     $x10000 = [ 0x10000 ]; $b = 'b16';
  2227.     }
  2228.   else
  2229.     {
  2230.     $x10000 = [ 0x1000 ]; $b = 'b12';
  2231.     }
  2232.   while (!(@$x1 == 1 && $x1->[0] == 0))        # _is_zero()
  2233.     {
  2234.     ($x1, $xr) = _div($c,$x1,$x10000);
  2235.     $es .= unpack($b,pack('v',$xr->[0]));
  2236.     }
  2237.   $es = reverse $es;
  2238.   $es =~ s/^[0]+//;   # strip leading zeros
  2239.   '0b' . $es;                    # return result prepended with 0b
  2240.   }
  2241.  
  2242. sub _as_oct
  2243.   {
  2244.   # convert a decimal number to octal (ref to array, return ref to string)
  2245.   my ($c,$x) = @_;
  2246.  
  2247.   # fits into one element (handle also 0 case)
  2248.   return sprintf("0%o",$x->[0]) if @$x == 1;
  2249.  
  2250.   my $x1 = _copy($c,$x);
  2251.  
  2252.   my $es = '';
  2253.   my $xr;
  2254.   my $x1000 = [ 0100000 ];
  2255.   while (@$x1 != 1 || $x1->[0] != 0)        # _is_zero()
  2256.     {
  2257.     ($x1, $xr) = _div($c,$x1,$x1000);
  2258.     $es .= reverse sprintf("%05o", $xr->[0]);
  2259.     }
  2260.   $es = reverse $es;
  2261.   $es =~ s/^[0]+//;   # strip leading zeros
  2262.   '0' . $es;                    # return result prepended with 0
  2263.   }
  2264.  
  2265. sub _from_oct
  2266.   {
  2267.   # convert a octal number to decimal (string, return ref to array)
  2268.   my ($c,$os) = @_;
  2269.  
  2270.   # for older Perls, play safe
  2271.   my $m = [ 0100000 ];
  2272.   my $d = 5;                    # 5 digits at a time
  2273.  
  2274.   my $mul = _one();
  2275.   my $x = _zero();
  2276.  
  2277.   my $len = int( (length($os)-1)/$d );        # $d digit parts, w/o the '0'
  2278.   my $val; my $i = -$d;
  2279.   while ($len >= 0)
  2280.     {
  2281.     $val = substr($os,$i,$d);            # get oct digits
  2282.     $val = CORE::oct($val);
  2283.     $i -= $d; $len --;
  2284.     my $adder = [ $val ];
  2285.     _add ($c, $x, _mul ($c, $adder, $mul ) ) if $val != 0;
  2286.     _mul ($c, $mul, $m ) if $len >= 0;         # skip last mul
  2287.     }
  2288.   $x;
  2289.   }
  2290.  
  2291. sub _from_hex
  2292.   {
  2293.   # convert a hex number to decimal (string, return ref to array)
  2294.   my ($c,$hs) = @_;
  2295.  
  2296.   my $m = _new($c, 0x10000000);            # 28 bit at a time (<32 bit!)
  2297.   my $d = 7;                    # 7 digits at a time
  2298.   if ($] <= 5.006)
  2299.     {
  2300.     # for older Perls, play safe
  2301.     $m = [ 0x10000 ];                # 16 bit at a time (<32 bit!)
  2302.     $d = 4;                    # 4 digits at a time
  2303.     }
  2304.  
  2305.   my $mul = _one();
  2306.   my $x = _zero();
  2307.  
  2308.   my $len = int( (length($hs)-2)/$d );        # $d digit parts, w/o the '0x'
  2309.   my $val; my $i = -$d;
  2310.   while ($len >= 0)
  2311.     {
  2312.     $val = substr($hs,$i,$d);            # get hex digits
  2313.     $val =~ s/^0x// if $len == 0;        # for last part only because
  2314.     $val = CORE::hex($val);            # hex does not like wrong chars
  2315.     $i -= $d; $len --;
  2316.     my $adder = [ $val ];
  2317.     # if the resulting number was to big to fit into one element, create a
  2318.     # two-element version (bug found by Mark Lakata - Thanx!)
  2319.     if (CORE::length($val) > $BASE_LEN)
  2320.       {
  2321.       $adder = _new($c,$val);
  2322.       }
  2323.     _add ($c, $x, _mul ($c, $adder, $mul ) ) if $val != 0;
  2324.     _mul ($c, $mul, $m ) if $len >= 0;         # skip last mul
  2325.     }
  2326.   $x;
  2327.   }
  2328.  
  2329. sub _from_bin
  2330.   {
  2331.   # convert a hex number to decimal (string, return ref to array)
  2332.   my ($c,$bs) = @_;
  2333.  
  2334.   # instead of converting X (8) bit at a time, it is faster to "convert" the
  2335.   # number to hex, and then call _from_hex.
  2336.  
  2337.   my $hs = $bs;
  2338.   $hs =~ s/^[+-]?0b//;                    # remove sign and 0b
  2339.   my $l = length($hs);                    # bits
  2340.   $hs = '0' x (8-($l % 8)) . $hs if ($l % 8) != 0;    # padd left side w/ 0
  2341.   my $h = '0x' . unpack('H*', pack ('B*', $hs));    # repack as hex
  2342.   
  2343.   $c->_from_hex($h);
  2344.   }
  2345.  
  2346. ##############################################################################
  2347. # special modulus functions
  2348.  
  2349. sub _modinv
  2350.   {
  2351.   # modular inverse
  2352.   my ($c,$x,$y) = @_;
  2353.  
  2354.   my $u = _zero($c); my $u1 = _one($c);
  2355.   my $a = _copy($c,$y); my $b = _copy($c,$x);
  2356.  
  2357.   # Euclid's Algorithm for bgcd(), only that we calc bgcd() ($a) and the
  2358.   # result ($u) at the same time. See comments in BigInt for why this works.
  2359.   my $q;
  2360.   ($a, $q, $b) = ($b, _div($c,$a,$b));        # step 1
  2361.   my $sign = 1;
  2362.   while (!_is_zero($c,$b))
  2363.     {
  2364.     my $t = _add($c,                 # step 2:
  2365.        _mul($c,_copy($c,$u1), $q) ,        #  t =  u1 * q
  2366.        $u );                    #     + u
  2367.     $u = $u1;                    #  u = u1, u1 = t
  2368.     $u1 = $t;
  2369.     $sign = -$sign;
  2370.     ($a, $q, $b) = ($b, _div($c,$a,$b));    # step 1
  2371.     }
  2372.  
  2373.   # if the gcd is not 1, then return NaN
  2374.   return (undef,undef) unless _is_one($c,$a);
  2375.  
  2376.   ($u1, $sign == 1 ? '+' : '-');
  2377.   }
  2378.  
  2379. sub _modpow
  2380.   {
  2381.   # modulus of power ($x ** $y) % $z
  2382.   my ($c,$num,$exp,$mod) = @_;
  2383.  
  2384.   # in the trivial case,
  2385.   if (_is_one($c,$mod))
  2386.     {
  2387.     splice @$num,0,1; $num->[0] = 0;
  2388.     return $num;
  2389.     }
  2390.   if ((scalar @$num == 1) && (($num->[0] == 0) || ($num->[0] == 1)))
  2391.     {
  2392.     $num->[0] = 1;
  2393.     return $num;
  2394.     }
  2395.  
  2396. #  $num = _mod($c,$num,$mod);    # this does not make it faster
  2397.  
  2398.   my $acc = _copy($c,$num); my $t = _one();
  2399.  
  2400.   my $expbin = _as_bin($c,$exp); $expbin =~ s/^0b//;
  2401.   my $len = length($expbin);
  2402.   while (--$len >= 0)
  2403.     {
  2404.     if ( substr($expbin,$len,1) eq '1')            # is_odd
  2405.       {
  2406.       _mul($c,$t,$acc);
  2407.       $t = _mod($c,$t,$mod);
  2408.       }
  2409.     _mul($c,$acc,$acc);
  2410.     $acc = _mod($c,$acc,$mod);
  2411.     }
  2412.   @$num = @$t;
  2413.   $num;
  2414.   }
  2415.  
  2416. sub _gcd
  2417.   {
  2418.   # greatest common divisor
  2419.   my ($c,$x,$y) = @_;
  2420.  
  2421.   while ( (scalar @$y != 1) || ($y->[0] != 0) )        # while ($y != 0)
  2422.     {
  2423.     my $t = _copy($c,$y);
  2424.     $y = _mod($c, $x, $y);
  2425.     $x = $t;
  2426.     }
  2427.   $x;
  2428.   }
  2429.  
  2430. ##############################################################################
  2431. ##############################################################################
  2432.  
  2433. 1;
  2434. __END__
  2435.  
  2436. =head1 NAME
  2437.  
  2438. Math::BigInt::Calc - Pure Perl module to support Math::BigInt
  2439.  
  2440. =head1 SYNOPSIS
  2441.  
  2442. Provides support for big integer calculations. Not intended to be used by other
  2443. modules. Other modules which sport the same functions can also be used to support
  2444. Math::BigInt, like Math::BigInt::GMP or Math::BigInt::Pari.
  2445.  
  2446. =head1 DESCRIPTION
  2447.  
  2448. In order to allow for multiple big integer libraries, Math::BigInt was
  2449. rewritten to use library modules for core math routines. Any module which
  2450. follows the same API as this can be used instead by using the following:
  2451.  
  2452.     use Math::BigInt lib => 'libname';
  2453.  
  2454. 'libname' is either the long name ('Math::BigInt::Pari'), or only the short
  2455. version like 'Pari'.
  2456.  
  2457. =head1 STORAGE
  2458.  
  2459. =head1 METHODS
  2460.  
  2461. The following functions MUST be defined in order to support the use by
  2462. Math::BigInt v1.70 or later:
  2463.  
  2464.     api_version()    return API version, 1 for v1.70, 2 for v1.83
  2465.     _new(string)    return ref to new object from ref to decimal string
  2466.     _zero()        return a new object with value 0
  2467.     _one()        return a new object with value 1
  2468.     _two()        return a new object with value 2
  2469.     _ten()        return a new object with value 10
  2470.  
  2471.     _str(obj)    return ref to a string representing the object
  2472.     _num(obj)    returns a Perl integer/floating point number
  2473.             NOTE: because of Perl numeric notation defaults,
  2474.             the _num'ified obj may lose accuracy due to 
  2475.             machine-dependent floating point size limitations
  2476.                     
  2477.     _add(obj,obj)    Simple addition of two objects
  2478.     _mul(obj,obj)    Multiplication of two objects
  2479.     _div(obj,obj)    Division of the 1st object by the 2nd
  2480.             In list context, returns (result,remainder).
  2481.             NOTE: this is integer math, so no
  2482.             fractional part will be returned.
  2483.             The second operand will be not be 0, so no need to
  2484.             check for that.
  2485.     _sub(obj,obj)    Simple subtraction of 1 object from another
  2486.             a third, optional parameter indicates that the params
  2487.             are swapped. In this case, the first param needs to
  2488.             be preserved, while you can destroy the second.
  2489.             sub (x,y,1) => return x - y and keep x intact!
  2490.     _dec(obj)    decrement object by one (input is guaranteed to be > 0)
  2491.     _inc(obj)    increment object by one
  2492.  
  2493.  
  2494.     _acmp(obj,obj)    <=> operator for objects (return -1, 0 or 1)
  2495.  
  2496.     _len(obj)    returns count of the decimal digits of the object
  2497.     _digit(obj,n)    returns the n'th decimal digit of object
  2498.  
  2499.     _is_one(obj)    return true if argument is 1
  2500.     _is_two(obj)    return true if argument is 2
  2501.     _is_ten(obj)    return true if argument is 10
  2502.     _is_zero(obj)    return true if argument is 0
  2503.     _is_even(obj)    return true if argument is even (0,2,4,6..)
  2504.     _is_odd(obj)    return true if argument is odd (1,3,5,7..)
  2505.  
  2506.     _copy        return a ref to a true copy of the object
  2507.  
  2508.     _check(obj)    check whether internal representation is still intact
  2509.             return 0 for ok, otherwise error message as string
  2510.  
  2511.     _from_hex(str)    return new object from a hexadecimal string
  2512.     _from_bin(str)    return new object from a binary string
  2513.     _from_oct(str)    return new object from an octal string
  2514.     
  2515.     _as_hex(str)    return string containing the value as
  2516.             unsigned hex string, with the '0x' prepended.
  2517.             Leading zeros must be stripped.
  2518.     _as_bin(str)    Like as_hex, only as binary string containing only
  2519.             zeros and ones. Leading zeros must be stripped and a
  2520.             '0b' must be prepended.
  2521.     
  2522.     _rsft(obj,N,B)    shift object in base B by N 'digits' right
  2523.     _lsft(obj,N,B)    shift object in base B by N 'digits' left
  2524.     
  2525.     _xor(obj1,obj2)    XOR (bit-wise) object 1 with object 2
  2526.             Note: XOR, AND and OR pad with zeros if size mismatches
  2527.     _and(obj1,obj2)    AND (bit-wise) object 1 with object 2
  2528.     _or(obj1,obj2)    OR (bit-wise) object 1 with object 2
  2529.  
  2530.     _mod(obj1,obj2)    Return remainder of div of the 1st by the 2nd object
  2531.     _sqrt(obj)    return the square root of object (truncated to int)
  2532.     _root(obj)    return the n'th (n >= 3) root of obj (truncated to int)
  2533.     _fac(obj)    return factorial of object 1 (1*2*3*4..)
  2534.     _pow(obj1,obj2)    return object 1 to the power of object 2
  2535.             return undef for NaN
  2536.     _zeros(obj)    return number of trailing decimal zeros
  2537.     _modinv        return inverse modulus
  2538.     _modpow        return modulus of power ($x ** $y) % $z
  2539.     _log_int(X,N)    calculate integer log() of X in base N
  2540.             X >= 0, N >= 0 (return undef for NaN)
  2541.             returns (RESULT, EXACT) where EXACT is:
  2542.              1     : result is exactly RESULT
  2543.              0     : result was truncated to RESULT
  2544.              undef : unknown whether result is exactly RESULT
  2545.         _gcd(obj,obj)    return Greatest Common Divisor of two objects
  2546.  
  2547. The following functions are REQUIRED for an api_version of 2 or greater:
  2548.  
  2549.     _1ex($x)    create the number 1Ex where x >= 0
  2550.     _alen(obj)    returns approximate count of the decimal digits of the
  2551.             object. This estimate MUST always be greater or equal
  2552.             to what _len() returns.
  2553.         _nok(n,k)    calculate n over k (binomial coefficient)
  2554.  
  2555. The following functions are optional, and can be defined if the underlying lib
  2556. has a fast way to do them. If undefined, Math::BigInt will use pure Perl (hence
  2557. slow) fallback routines to emulate these:
  2558.     
  2559.     _signed_or
  2560.     _signed_and
  2561.     _signed_xor
  2562.  
  2563. Input strings come in as unsigned but with prefix (i.e. as '123', '0xabc'
  2564. or '0b1101').
  2565.  
  2566. So the library needs only to deal with unsigned big integers. Testing of input
  2567. parameter validity is done by the caller, so you need not worry about
  2568. underflow (f.i. in C<_sub()>, C<_dec()>) nor about division by zero or similar
  2569. cases.
  2570.  
  2571. The first parameter can be modified, that includes the possibility that you
  2572. return a reference to a completely different object instead. Although keeping
  2573. the reference and just changing its contents is preferred over creating and
  2574. returning a different reference.
  2575.  
  2576. Return values are always references to objects, strings, or true/false for
  2577. comparison routines.
  2578.  
  2579. =head1 WRAP YOUR OWN
  2580.  
  2581. If you want to port your own favourite c-lib for big numbers to the
  2582. Math::BigInt interface, you can take any of the already existing modules as
  2583. a rough guideline. You should really wrap up the latest BigInt and BigFloat
  2584. testsuites with your module, and replace in them any of the following:
  2585.  
  2586.     use Math::BigInt;
  2587.  
  2588. by this:
  2589.  
  2590.     use Math::BigInt lib => 'yourlib';
  2591.  
  2592. This way you ensure that your library really works 100% within Math::BigInt.
  2593.  
  2594. =head1 LICENSE
  2595.  
  2596. This program is free software; you may redistribute it and/or modify it under
  2597. the same terms as Perl itself. 
  2598.  
  2599. =head1 AUTHORS
  2600.  
  2601. Original math code by Mark Biggar, rewritten by Tels L<http://bloodgate.com/>
  2602. in late 2000.
  2603. Seperated from BigInt and shaped API with the help of John Peacock.
  2604.  
  2605. Fixed, speed-up, streamlined and enhanced by Tels 2001 - 2007.
  2606.  
  2607. =head1 SEE ALSO
  2608.  
  2609. L<Math::BigInt>, L<Math::BigFloat>,
  2610. L<Math::BigInt::GMP>, L<Math::BigInt::FastCalc> and L<Math::BigInt::Pari>.
  2611.  
  2612. =cut
  2613.